/*
 * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
 *
 * Copyright (C) 2024 Gordon Williams <gw@pur3.co.uk>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * ----------------------------------------------------------------------------
 * This file is designed to be parsed during the build process
 *
 * Contains JavaScript interface for Pipboy
 *
 * ----------------------------------------------------------------------------
 */
/* DO_NOT_INCLUDE_IN_DOCS - this is a special token for common.py */


#include "jswrap_pipboy.h"
#include "platform_config.h"
#include "jsinteractive.h"
#include "jsdevices.h"
#include "jshardware.h"
#include "jswrap_graphics.h"
#include "jswrap_interactive.h"
#include "jswrap_espruino.h"
#include "jspin.h"
#include "jsflags.h"
#include "jshardware.h"
#include "jswrap_fs.h"
#include "jswrap_file.h"
#include "graphics.h"
#include "stm32_i2s.h"
#ifndef LINUX
#include "stm32f4xx_sdio.h"
#include "lcd_fsmc.h"
#endif

#include "avi.h"

#define DAC_SCL_PIN (JSH_PORTB_COUNT+8)
#define DAC_SDA_PIN (JSH_PORTB_COUNT+9)
#define RADIO_SCL_PIN (JSH_PORTB_COUNT+6)
#define RADIO_SDA_PIN (JSH_PORTB_COUNT+7)

#define STREAM_BUFFER_SIZE 40960
uint8_t streamBuffer[STREAM_BUFFER_SIZE+4] __attribute__ ((aligned (8))); // we add 4 to allow our unaligned fread hack to work
// Can't go in 64k CCM RAM because no DMA is allowed to CCM!
// Maybe if we modified DMA to read to a buffer first?

/** Palette for scanlines
0: even (bright line)
1: odd (dark line)
0: even scan effect
1: odd scan effect
 */
uint16_t palette[4][16];

bool videoStream = false;
bool audioStream = false;
int streamBufferLen;
uint16_t streamPacketId;
uint32_t streamPacketLen;        // length of current stream
uint32_t streamPacketRemaining;  // length left to read in current stream
uint32_t streamPacketBufferLen;  // length of stream in current buffer
File_Handle videoFile; // The Video/Audio stream's file
File_Handle audioFile; // The Video/Audio stream's file
bool videoRepeats; // should this stream repeat?
bool audioRepeats; // should this stream repeat?

JsSysTime videoFrameTime;
JsSysTime videoNextFrameTime;
bool debugInfo = false;
int startX=0;
int startY=0;
AviInfo videoInfo;
WavInfo audioInfo;

typedef enum {
  DM_OFF,
  DM_Output
} DACMode;


#ifdef LINUX // Linux -> FatFS hacks
#define FR_NO_FILE 4
#define FR_NOT_ENABLED 12
void f_close(File_Handle *f) {
  fclose(*f);
}
void f_lseek(File_Handle *f, uint32_t offset) {
  fseek(*f, offset, SEEK_SET);
}
FRESULT f_read(File_Handle* fp, void* buff, uint32_t btr, size_t* br) {
  assert((((size_t)buff)&7)==0);
  *br = fread(buff, 1, btr, *fp);
  return *br!=0;
}
uint32_t f_size(File_Handle *f) {
  fseek(*f, 0, SEEK_END);
  return ftell(*f);
}
#else // not LINUX


#endif

/*JSON{
    "type": "class",
    "class" : "Pip"
}
*/
/*JSON{
  "type" : "event",
  "class" : "Pip",
  "name" : "streamStarted"
}
The video had started
*/
/*JSON{
  "type" : "event",
  "class" : "Pip",
  "name" : "streamStopped"
}
The video had ended
*/
/*JSON{
  "type" : "event",
  "class" : "Pip",
  "name" : "audioStopped"
}
The audio had ended
*/
/*JSON{
  "type" : "event",
  "class" : "Pip",
  "name" : "videoStopped"
}
The video had ended
*/
/*JSON{
  "type" : "event",
  "class" : "Pip",
  "name" : "streamLooped"
}
The video had looped
*/
void jswrap_pb_sendEvent(const char *eventName) { // eg JS_EVENT_PREFIX"streamStarted"
   JsVar *pip =jsvObjectGetChildIfExists(execInfo.root, "Pip");
  if (pip) {
    jsiQueueObjectCallbacks(pip, eventName, NULL, 0);
    jsvUnLock(pip);
  }
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "videoStart",
  "generate" : "jswrap_pb_videoStart",
  "params" : [
      ["fn","JsVar","Filename"],
      ["options","JsVar","[Optional] object `{x:0, y:0, debug:false, repeat:false}`"]
   ]
}
*/
void jswrap_pb_videoStart(JsVar *fn, JsVar *options) {

  startX=0;
  startY=0;
  debugInfo=false;
  videoRepeats=false;
  JsVar *v;
  if (jsvIsObject(options)) {
    v = jsvObjectGetChildIfExists(options, "x");
    if (v) {
      startX = jsvGetIntegerAndUnLock(v);
    }
    v = jsvObjectGetChildIfExists(options, "y");
    if (v) {
      startY = jsvGetIntegerAndUnLock(v);
    }
    v = jsvObjectGetChildIfExists(options, "debug");
    if (v) {
      if (jsvGetBoolAndUnLock(v)) debugInfo = true;
      else debugInfo = false;
    }
    videoRepeats = jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(options, "repeat"));
  }

  char pathStr[JS_DIR_BUF_SIZE] = "";
  if (!jsfsGetPathString(pathStr, fn)) return;
  if (debugInfo) {
    jsiConsolePrintf("Playing video %s at x0=%d, y0=%d\n", pathStr, startX, startY);
  }

  if (jsfsInit()) {
    if (videoStream) {
      f_close(&videoFile);
      videoStream = false;
    }

    FRESULT res;
#ifdef LINUX
    if ((videoFile = fopen(pathStr, "r"))) {
#else
    BYTE ff_mode = FA_READ | FA_OPEN_EXISTING;
    if ((res=f_open(&videoFile, pathStr, ff_mode)) == FR_OK) {
#endif

      videoStream = true;
      size_t actual = 0;
      res = f_read(&videoFile, (uint8_t*)streamBuffer, STREAM_BUFFER_SIZE, &actual);
      if (debugInfo) {
        jsiConsolePrintf("AVI read %d %d %c%c%c%c\n", STREAM_BUFFER_SIZE, actual, streamBuffer[0],streamBuffer[1],streamBuffer[2],streamBuffer[3]);
      }
      if (aviLoad(streamBuffer, (int)actual, &videoInfo, debugInfo)) {
        streamPacketId = *(uint16_t*)&streamBuffer[videoInfo.streamOffset+2]; // +0 = '01'/'00' stream index?
        streamPacketLen = *(uint32_t*)&streamBuffer[videoInfo.streamOffset+4]; // +0 = '01'/'00' stream index?
        f_lseek(&videoFile, (uint32_t)(videoInfo.streamOffset+8)); // go back to start of video data
        videoFrameTime = jshGetTimeFromMilliseconds(videoInfo.usPerFrame/1000.0);
        videoNextFrameTime = jshGetSystemTime() + videoFrameTime;
        // set palette
        for (int i=0;i<256;i++) {
          uint16_t c = videoInfo.palette[i];
          uint16_t br = (c>>11)&0x1F;
          uint16_t bg = (c>>6)&0x1F;
          uint16_t bb = c&0x1F;
          uint16_t lum = br; // lum = 0..31
          if (bg>lum) lum=bg;
          if (bb>lum) lum=bb;
          // We use the non-scan-effect palette here (not idx 2) as it's too bright otherwise
          videoInfo.palette[i] = palette[0][lum>>1]; // Should blend so we don't lose 1 bit accuracy?
        }

#ifndef LINUX
        // Set up Audio
        if (videoInfo.audioBufferSize <= I2S_RING_BUFFER_SIZE*2) { // IF we have audio
          STM32_I2S_Prepare(videoInfo.audio.sampleRate);
          // playback will start when the buffer is full enough
        } else if (videoInfo.audioBufferSize) {
          jsiConsolePrintf("Audio stream too big (%db)\n", videoInfo.audioBufferSize);
        }
#endif
        jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamStarted");
      } else {
        jsExceptionHere(JSET_ERROR, "Corrupt video");
        jswrap_pb_videoStop();
      }
    } else {
      jsExceptionHere(JSET_ERROR, "Can't load file %s", pathStr);
    }
  } else {
    jsExceptionHere(JSET_ERROR, "Failed to init SD card");
  }
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "videoStop",
  "generate" : "jswrap_pb_videoStop"
}
*/
void jswrap_pb_videoStopLetAudioRun() {
  if (videoStream) {
    f_close(&videoFile);
    videoStream = false;
    jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamStopped");
    jswrap_pb_sendEvent(JS_EVENT_PREFIX"videoStopped");
  }
}
void jswrap_pb_videoStop() {
  if (videoStream && videoInfo.audioBufferSize) {
    STM32_I2S_Stop(); // Stop audio immediately
  }
  jswrap_pb_videoStopLetAudioRun();
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioStop",
  "generate" : "jswrap_pb_audioStop"
}
*/
void jswrap_pb_audioStopLetRun() {
  if (audioStream) {
    f_close(&audioFile);
    audioStream = false;
    jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamStopped");
    jswrap_pb_sendEvent(JS_EVENT_PREFIX"audioStopped");
  }
}
void jswrap_pb_audioStop() {
  if (audioStream) {
    STM32_I2S_Stop(); // Stop audio immediately
  }
  jswrap_pb_audioStopLetRun();
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioStart",
  "generate" : "jswrap_pb_audioStart",
  "params" : [
      ["fn","JsVar","Filename"],
      ["options","JsVar","[Optional] object `{debug:false, repeat:false}`"]
   ]
}
*/
void jswrap_pb_audioStart(JsVar *fn, JsVar *options) {
  debugInfo=false;
  audioRepeats=false;
  JsVar *v;
  if (jsvIsObject(options)) {
    v = jsvObjectGetChildIfExists(options, "debug");
    if (v) {
      if (jsvGetBoolAndUnLock(v)) debugInfo = true;
      else debugInfo = false;
    }
    audioRepeats = jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(options, "repeat"));
  }

  char pathStr[JS_DIR_BUF_SIZE] = "";
  if (!jsfsGetPathString(pathStr, fn)) return;

  if (jsfsInit()) {
    if (audioStream) {
      if (debugInfo) {
        jsiConsolePrintf("Closing existing stream\n");
      }
      f_close(&audioFile);
      audioStream = false;
    }

    if (debugInfo) {
      jsiConsolePrintf("Opening audio file %s\n", pathStr);
    }
    FRESULT res;
#ifdef LINUX
    if ((audioFile = fopen(pathStr, "r"))) {
#else
    BYTE ff_mode = FA_READ | FA_OPEN_EXISTING;
    if ((res=f_open(&audioFile, pathStr, ff_mode)) == FR_OK) {
#endif
      if (debugInfo) {
        jsiConsolePrintf("Opened audio file OK - reading WAV header\n");
      }
      audioStream = true;
      size_t actual = 0;
      const int WAVHEADER_MAX = 256;
      res = f_read(&audioFile, (uint8_t*)streamBuffer, WAVHEADER_MAX, &actual);
      if (debugInfo) {
        jsiConsolePrintf("WAV read %d %d %c%c%c%c\n", WAVHEADER_MAX, actual, streamBuffer[0],streamBuffer[1],streamBuffer[2],streamBuffer[3]);
      }
      if (wavLoad(streamBuffer, (int)actual, &audioInfo, debugInfo)) {
        f_lseek(&audioFile, (uint32_t)(audioInfo.streamOffset)); // go back to start of audio data
        STM32_I2S_Prepare(audioInfo.sampleRate);
        jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamStarted");
        if (debugInfo) jsiConsolePrintf("Audio started...\n");
      } else {
        jsExceptionHere(JSET_ERROR, "Corrupt audio");
        jswrap_pb_audioStop();
      }
    } else {
      jsExceptionHere(JSET_ERROR, "Can't load file %s", pathStr);
    }
  } else {
    jsExceptionHere(JSET_ERROR, "Failed to init SD card");
  }
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioRead",
  "generate" : "jswrap_pb_audioRead",
  "params" : [
      ["fn","JsVar","Filename"],
      ["returnOptions","JsVar","If an object is supplied, it'll be filled with `encoding` and `blockAlign` fields ready for `Pip.audioStartVar`"]
   ],
   "return" : ["JsVar","The raw sound data as a flat string"]
}
Read the given WAV file into RAM
*/
JsVar *jswrap_pb_audioRead(JsVar *fn, JsVar *returnOptions) {
  char pathStr[JS_DIR_BUF_SIZE] = "";
  if (!jsfsGetPathString(pathStr, fn)) return 0;

  if (jsfsInit()) {
    FRESULT res;
    File_Handle file;
#ifdef LINUX
    if ((file = fopen(pathStr, "r"))) {
#else
    BYTE ff_mode = FA_READ | FA_OPEN_EXISTING;
    if ((res=f_open(&file, pathStr, ff_mode)) == FR_OK) {
#endif
      if (debugInfo) {
        jsiConsolePrintf("Opened audio file OK - reading WAV header\n");
      }
      size_t actual = 0;
      const int WAVHEADER_MAX = 256;
      uint8_t buf[256];
      WavInfo wavInfo;
      res = f_read(&file, (uint8_t*)buf, WAVHEADER_MAX, &actual);
      if (wavLoad(buf, (int)actual, &wavInfo, debugInfo)) {
        if (jsvIsObject(returnOptions)) {
          if (wavInfo.sampleRate!=16000)
            jsvObjectSetChildAndUnLock(returnOptions, "sampleRate", jsvNewFromInteger(wavInfo.sampleRate));
          if (wavInfo.formatTag == WAVFMT_RAW)
            jsvObjectSetChildAndUnLock(returnOptions, "encoding", jsvNewFromInteger(wavInfo.sampleSize));
          else if (wavInfo.formatTag == WAVFMT_IMA_ADPCM) {
            jsvObjectSetChildAndUnLock(returnOptions, "encoding", jsvNewFromString("adpcm"));
            jsvObjectSetChildAndUnLock(returnOptions, "blockAlign", jsvNewFromInteger(wavInfo.blockAlign));
          }
        }
        f_lseek(&file, (uint32_t)(wavInfo.streamOffset)); // go back to start of audio data
        uint32_t len = f_size(&file) - (uint32_t)wavInfo.streamOffset;
        JsVar *buffer = jsvNewFlatStringOfLength(len);
        if (!buffer) {
          jsExceptionHere(JSET_ERROR, "Couldn't allocate flat string of size %d", len);
          return 0;
        }
        f_read(&file, jsvGetFlatStringPointer(buffer), len, &actual);
        return buffer;
      } else {
        jsExceptionHere(JSET_ERROR, "Corrupt audio");
      }
      f_close(&file);
    } else {
      jsExceptionHere(JSET_ERROR, "Can't load file %s", pathStr);
    }
  } else {
    jsExceptionHere(JSET_ERROR, "Failed to init SD card");
  }
  return 0;
}



/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioBuiltin",
  "generate" : "jswrap_pb_audioBuiltin",
  "params" : [
      ["id","JsVar","OK/OK2/PREV/NEXT/COLUMN/CLICK"]
   ],
   "return" : ["JsVar","The sound as a native string"]
}
Return the builtin sound
*/
JsVar *jswrap_pb_audioBuiltin(JsVar *id) {
/*
v = Pip.audioRead("UI/OK.wav");
for (var i=0;i<v.length;i+=160) {
  print(E.toUint8Array(v.substr(i,160)).join(",")+",");
}
for (var i=0;i<v.length;i+=160) {
  console.log(v.substr(i,160).split("").map(f=>f.charCodeAt()).join(",")+",");
}
*/
  static const unsigned char wav_ok[] = {0,0,1,0,254,255,250,255,0,0,255,255,4,0,
7,0,7,0,3,0,252,255,247,255,247,255,250,255,255,255,0,0,3,0,8,0,6,0,3,0,254,255,254,255,251,255,249,255,248,255,249,255,3,0,7,0,12,0,17,0,12,0,247,255,240,255,247,255,244,255,237,255,2,0,14,0,11,0,13,0,22,0,249,255,253,255,10,0,255,255,13,0,6,0,227,255,244,255,229,255,206,255,229,255,14,0,5,0,57,0,67,0,36,0,63,0,252,255,223,255,191,255,170,255,196,255,250,255,42,0,45,0,102,0,60,0,14,0,252,255,4,0,207,255,139,255,72,255,241,255,131,0,230,255,162,255,227,255,166,0,234,0,177,255,198,253,143,255,234,0,100,2,111,4,
184,1,102,255,93,252,250,250,207,252,62,254,104,255,38,3,29,5,52,4,215,2,152,0,240,253,141,251,49,251,3,251,245,252,47,0,246,3,43,6,120,5,37,4,241,1,23,255,18,252,188,250,35,250,44,252,90,0,66,3,172,4,45,4,17,3,120,1,199,254,129,251,116,250,48,251,83,254,233,2,42,4,1,4,33,4,248,2,243,0,123,254,201,251,74,251,25,252,248,252,9,255,221,1,209,4,248,5,127,4,21,2,47,255,104,252,113,251,242,251,250,252,155,254,172,0,121,2,173,3,36,3,17,1,165,255,191,254,47,253,15,253,46,254,191,255,139,1,153,2,209,2,194,1,106,0,3,255,174,253,
238,252,107,254,26,1,90,3,26,4,53,3,129,1,117,255,203,252,63,251,31,252,33,254,230,255,17,1,14,2,123,2,157,1,246,255,163,254,26,254,62,254,61,255,18,1,93,2,170,2,221,2,103,2,19,1,154,254,59,252,243,251,64,253,220,254,34,0,209,0,231,0,119,0,233,255,228,255,50,0,89,0,198,0,130,1,216,1,37,2,5,2,77,1,170,255,76,254,131,253,171,253,124,254,211,254,109,255,25,0,255,255,141,255,4,255,237,254,116,255,76,0,128,1,4,2,3,2,239,1,45,1,27,0,68,255,164,254,11,255,37,0,169,0,97,0,38,0,238,255,90,255,11,255,42,255,159,255,147,0,
75,1,114,1,17,1,147,0,102,0,93,0,49,0,112,255,46,254,24,254,21,255,227,255,252,255,86,255,105,254,237,253,46,254,176,254,80,255,128,0,161,1,130,2,184,2,230,1,127,1,154,1,77,1,207,0,89,0,12,0,22,0,63,0,29,0,39,255,84,254,37,254,58,254,209,254,78,255,181,255,61,0,220,0,56,1,193,0,210,255,88,255,71,255,151,255,208,255,57,255,16,255,81,255,198,255,249,255,88,0,106,0,89,0,45,0,211,255,167,255,63,255,39,255,214,255,131,1,133,2,113,2,109,2,90,2,106,1,237,255,111,254,18,254,158,254,232,254,77,255,242,255,214,0,63,1,248,0,35,0,
14,255,211,253,98,253,6,253,253,252,160,253,239,254,159,0,7,2,149,2,41,2,67,1,188,0,229,0,53,1,63,1,134,0,22,0,167,255,101,255,95,255,150,255,52,0,164,0,149,0,59,0,10,0,225,255,207,255,183,255,178,255,58,0,194,0,78,1,112,1,71,1,191,0,165,255,124,254,10,254,188,253,140,253,226,253,136,254,99,255,154,255,130,255,193,255,76,0,155,0,250,0,135,1,160,1,230,1,24,2,161,1,185,0,214,255,41,255,219,254,220,254,238,254,236,254,26,255,114,255,195,255,226,255,214,255,34,0,137,0,221,0,65,1,96,1,76,1,9,1,131,0,240,255,120,255,255,254,193,254,
190,254,232,254,31,255,139,255,72,0,178,0,133,0,232,255,91,255,84,255,209,255,117,0,240,0,65,1,71,1,19,1,175,0,253,255,158,255,141,255,95,255,249,254,151,254,122,254,152,254,244,254,107,255,237,255,146,0,236,0,81,1,140,1,151,1,168,1,98,1,179,0,43,0,207,255,166,255,241,255,53,0,237,255,122,255,79,255,85,255,126,255,91,255,27,255,9,255,239,254,10,255,54,255,91,255,166,255,34,0,143,0,189,0,182,0,208,0,180,0,131,0,41,0,213,255,213,255,217,255,30,0,136,0,108,0,52,0,232,255,183,255,117,255,76,255,184,255,31,0,217,0,85,1,62,1,28,1,16,1,
240,0,143,0,224,255,9,255,159,254,191,254,24,255,71,255,99,255,149,255,190,255,181,255,85,255,198,254,223,254,69,255,210,255,70,0,140,0,49,1,144,1,169,1,184,1,103,1,251,0,122,0,44,0,189,255,247,254,88,254,63,254,172,254,15,255,122,255,30,0,131,0,185,0,176,0,64,0,220,255,122,255,67,255,86,255,193,255,87,0,240,0,108,1,134,1,66,1,158,0,187,255,242,254,177,254,226,254,78,255,154,255,226,255,17,0,2,0,215,255,184,255,219,255,74,0,158,0,242,0,54,1,43,1,48,1,4,1,109,0,150,255,234,254,222,254,40,255,79,255,57,255,230,254,198,254,221,254,102,255,
216,255,3,0,142,0,35,1,167,1,91,1,176,0,70,0,244,255,170,255,119,255,117,255,196,255,7,0,56,0,74,0,17,0,26,0,44,0,64,0,34,0,15,0,2,0,254,255,10,0,241,255,237,255,56,0,198,0,202,0,162,0,45,0,145,255,6,255,199,254,198,254,163,254,185,254,114,255,91,0,227,0,13,1,246,0,233,0,139,0,241,255,84,255,57,255,105,255,227,255,118,0,207,0,222,0,101,0,218,255,68,255,198,254,161,254,254,254,169,255,52,0,129,0,182,0,205,0,237,0,177,0,67,0,206,255,124,255,193,255,69,0,181,0,224,0,193,0,107,0,242,255,135,255,48,255,255,254,33,255,
133,255,238,255,70,0,102,0,121,0,115,0,88,0,58,0,37,0,18,0,7,0,249,255,192,255,180,255,197,255,237,255,233,255,188,255,178,255,170,255,149,255,119,255,147,255,197,255,213,255,0,0,73,0,110,0,164,0,168,0,155,0,159,0,109,0,99,0,96,0,39,0,203,255,156,255,141,255,89,255,46,255,56,255,114,255,163,255,197,255,23,0,104,0,145,0,144,0,123,0,92,0,56,0,45,0,72,0,49,0,11,0,224,255,202,255,202,255,174,255,144,255,94,255,97,255,166,255,1,0,27,0,72,0,144,0,141,0,121,0,82,0,47,0,29,0,48,0,68,0,41,0,243,255,230,255,1,0,245,255,
193,255,114,255,54,255,51,255,109,255,177,255,242,255,61,0,120,0,167,0,194,0,189,0,135,0,70,0,22,0,220,255,179,255,170,255,181,255,187,255,177,255,140,255,138,255,173,255,196,255,227,255,24,0,62,0,78,0,77,0,80,0,86,0,84,0,87,0,85,0,44,0,7,0,238,255,192,255,141,255,107,255,124,255,164,255,183,255,232,255,62,0,115,0,131,0,126,0,78,0,40,0,5,0,218,255,224,255,1,0,10,0,16,0,30,0,37,0,10,0,240,255,201,255,177,255,156,255,114,255,121,255,125,255,172,255,255,255,60,0,112,0,144,0,138,0,112,0,66,0,20,0,233,255,228,255,246,255,2,0,
19,0,28,0,29,0,27,0,253,255,225,255,194,255,165,255,199,255,238,255,245,255,240,255,7,0,24,0,26,0,4,0,251,255,6,0,19,0,29,0,22,0,19,0,253,255,239,255,227,255,199,255,164,255,152,255,176,255,203,255,237,255,22,0,68,0,103,0,128,0,122,0,109,0,75,0,20,0,242,255,237,255,254,255,246,255,0,0,23,0,30,0,24,0,1,0,233,255,185,255,160,255,147,255,161,255,198,255,242,255,251,255,6,0,23,0,30,0,25,0,247,255,210,255,190,255,217,255,243,255,19,0,36,0,69,0,90,0,71,0,33,0,241,255,206,255,208,255,214,255,223,255,17,0,66,0,111,0,129,0,
124,0,93,0,48,0,252,255,217,255,197,255,188,255,180,255,192,255,210,255,227,255,238,255,241,255,236,255,220,255,199,255,196,255,208,255,224,255,247,255,11,0,41,0,55,0,58,0,39,0,24,0,17,0,32,0,31,0,237,255,192,255,188,255,220,255,252,255,14,0,17,0,36,0,45,0,41,0,36,0,41,0,42,0,16,0,246,255,235,255,247,255,2,0,10,0,25,0,18,0,247,255,229,255,211,255,164,255,142,255,154,255,184,255,227,255,16,0,45,0,74,0,86,0,71,0,50,0,41,0,31,0,17,0,254,255,3,0,8,0,255,255,252,255,255,255,249,255,248,255,236,255,220,255,208,255,202,255,205,255,
235,255,19,0,31,0,40,0,50,0,42,0,20,0,2,0,225,255,201,255,189,255,189,255,222,255,254,255,26,0,30,0,1,0,224,255,216,255,229,255,1,0,38,0,70,0,96,0,97,0,107,0,93,0,43,0,2,0,221,255,203,255,221,255,246,255,255,255,254,255,3,0,253,255,232,255,213,255,198,255,186,255,185,255,202,255,239,255,8,0,17,0,34,0,38,0,18,0,3,0,244,255,246,255,254,255,249,255,0,0,13,0,21,0,34,0,39,0,22,0,3,0,239,255,236,255,240,255,240,255,1,0,21,0,41,0,49,0,32,0,4,0,233,255,214,255,200,255,191,255,199,255,226,255,253,255,24,0,29,0,
19,0,11,0,13,0,12,0,250,255,240,255,252,255,28,0,44,0,35,0,23,0,5,0,241,255,218,255,208,255,218,255,241,255,10,0,33,0,33,0,23,0,7,0,250,255,241,255,218,255,205,255,216,255,240,255,4,0,13,0,26,0,43,0,53,0,53,0,42,0,26,0,2,0,248,255,237,255,226,255,227,255,237,255,239,255,246,255,253,255,255,255,4,0,8,0,13,0,7,0,3,0,254,255,252,255,1,0,4,0,7,0,1,0,0,0,7,0,3,0,252,255,253,255,244,255,238,255,228,255,220,255,217,255,228,255,254,255,13,0,39,0,47,0,42,0,31,0,17,0,8,0,250,255,247,255,2,0,18,0,
27,0,32,0,23,0,8,0,246,255,225,255,202,255,194,255,199,255,215,255,250,255,26,0,43,0,41,0,27,0,3,0,239,255,219,255,215,255,217,255,230,255,6,0,43,0,56,0,43,0,18,0,255,255,238,255,220,255,223,255,238,255,253,255,15,0,36,0,43,0,39,0,24,0,3,0,243,255,241,255,246,255,7,0,19,0,24,0,19,0,5,0,249,255,212,255,191,255,192,255,199,255,224,255,254,255,25,0,54,0,62,0,46,0,18,0,247,255,232,255,227,255,225,255,240,255,0,0,27,0,48,0,52,0,44,0,15,0,246,255,220,255,203,255,205,255,218,255,238,255,4,0,29,0,32,0,27,0,16,0,
0,0,238,255,228,255,225,255,237,255,253,255,8,0,14,0,14,0,3,0,255,255,251,255,251,255,1,0,11,0,23,0,31,0,31,0,32,0,30,0,16,0,252,255,233,255,229,255,232,255,239,255,240,255,239,255,242,255,247,255,249,255,252,255,247,255,243,255,250,255,1,0,11,0,17,0,20,0,14,0,7,0,2,0,255,255,250,255,248,255,249,255,248,255,240,255,236,255,241,255,247,255,247,255,253,255,6,0,19,0,34,0,38,0,38,0,29,0,11,0,2,0,249,255,245,255,241,255,248,255,251,255,250,255,247,255,241,255,235,255,232,255,236,255,243,255,251,255,255,255,10,0,24,0,29,0,27,0,16,0,
9,0,253,255,244,255,240,255,238,255,244,255,250,255,251,255,6,0,13,0,10,0,6,0,8,0,5,0,2,0,1,0,1,0,8,0,6,0,12,0,11,0,6,0,254,255,242,255,242,255,242,255,247,255,251,255,1,0,8,0,1,0,1,0,243,255,237,255,14,0,242,255,210,255,25,0,13,0,26,0,15,0,3,0,5,0,253,255,244,255,55,0,28,0,252,255,251,255,43,0,210,255,171,0,224,254,240,252,55,6,17,1,170,249,25,253,189,3,87,7,138,250,59,254,14,255,66,251,26,9,188,253,245,248,203,12,22,254,36,0,148,252,52,1,120,0,135,3,102,251,114,245,88,5,65,13,59,248,34,246,
19,14,198,250,140,246,212,13,170,242,203,4,22,8,41,242,132,2,210,6,205,246,111,249,25,14,183,0,239,248,3,8,17,254,163,255,222,6,62,255,91,255,58,4,173,0,73,246,108,15,211,255,18,248,190,6,79,246,75,250,131,3,221,251,90,252,152,255,80,253,89,252,41,4,133,1,197,2,77,253,80,254,71,7,49,3,208,2,89,3,203,3,3,2,136,255,242,0,214,252,1,251,98,252,40,253,146,254,142,1,153,0,173,255,32,2,59,0,165,251,5,253,190,2,94,0,46,254,230,255,101,2,222,252,19,250,231,1,114,2,74,3,166,0,210,255,115,12,159,254,152,248,170,11,50,255,35,10,120,248,
51,253,183,3,60,250,181,238,44,7,182,2,44,0,127,2,53,243,246,1,6,235,172,22,72,244,18,9,60,251,160,21,128,249,33,0,57,253,129,5,223,13,112,247,39,2,78,1,139,20,69,222,45,246,162,2,51,18,24,229,170,0,240,13,190,2,195,251,170,6,177,3,155,0,92,246,131,12,226,10,14,232,200,238,210,6,119,229,46,255,17,14,39,8,14,251,245,252,207,248,3,7,31,6,18,11,69,5,172,0,230,15,83,2,40,244,131,244,130,14,251,0,104,252,126,255,248,4,108,5,191,234,14,245,179,41,32,44,137,241,37,222,97,237,208,217,192,228,226,230,237,79,254,8,146,206,194,7,97,47,
135,30,120,70,183,249,209,225,104,63,97,248,40,209,1,0,111,200,6,134,220,39,105,39,10,1,49,50,15,244,46,175,112,237,100,54,175,247,135,222,116,9,185,8,82,3,167,15,30,19,89,16,168,252,58,33,73,49,62,15,168,255,199,245,0,237,25,224,249,251,39,11,96,254,71,222,221,234,59,4,164,252,47,10,144,19,145,245,223,252,124,33,222,24,74,250,241,214,111,216,16,230,220,230,186,226,103,11,125,21,110,243,118,219,63,243,144,9,80,35,212,60,95,55,44,31,41,30,30,43,212,25,246,230,205,212,191,234,229,220,247,212,38,0,255,5,69,253,82,236,114,232,164,43,104,61,211,32,105,2,
26,236,143,238,37,228,241,197,165,180,24,192,174,228,2,28,150,38,247,31,8,23,45,16,153,13,20,37,34,64,96,46,142,15,180,233,209,225,72,227,84,212,214,217,142,246,93,11,209,19,111,255,200,230,214,246,181,0,50,251,247,5,143,35,204,40,36,48,8,42,71,10,141,232,75,239,250,246,91,245,232,255,178,248,41,241,159,224,97,229,37,255,105,4,126,241,54,5,196,7,57,251,192,247,52,245,165,3,220,10,248,249,237,255,152,17,202,31,24,21,97,12,71,3,136,246,188,241,173,242,100,246,76,245,149,239,191,241,55,252,103,10,252,13,133,11,67,30,123,24,131,249,84,238,101,245,237,240,178,239,
205,238,25,6,255,22,16,22,255,15,127,19,207,15,48,249,91,231,134,232,63,241,215,233,126,226,225,229,19,229,195,242,35,1,225,3,4,9,57,7,176,14,74,30,163,33,239,37,145,40,228,35,81,17,113,246,101,235,98,243,208,249,247,253,3,248,90,222,196,224,248,237,239,241,135,238,95,235,205,246,106,17,230,34,148,27,253,19,64,16,136,8,18,255,179,252,63,0,49,10,74,4,20,249,136,244,61,245,22,237,126,224,12,226,19,247,111,0,86,250,65,246,1,250,52,254,136,5,237,10,44,16,80,20,39,22,78,25,244,23,56,20,124,13,210,11,101,5,135,249,123,252,184,247,237,238,55,239,224,238,
42,235,62,238,252,240,253,239,199,244,1,250,180,0,12,4,254,3,231,5,37,3,204,10,250,22,205,19,62,13,132,12,87,12,194,12,34,6,255,254,56,252,34,245,211,239,179,242,226,245,241,244,210,243,145,241,244,245,92,251,54,253,90,1,211,6,196,6,232,5,226,9,234,8,130,8,52,9,85,12,10,16,61,12,255,7,87,4,137,252,40,244,33,242,148,239,219,244,139,249,237,250,86,251,232,252,14,253,159,254,122,8,69,10,76,8,3,9,19,8,203,8,157,10,200,6,18,2,244,2,250,2,209,2,225,3,55,2,191,253,192,250,144,247,101,247,69,248,166,248,129,249,203,253,179,253,34,252,196,254,
105,255,138,255,243,0,79,0,138,1,89,5,157,4,235,0,191,255,191,1,45,3,63,2,30,255,230,254,174,254,246,253,54,252,85,249,51,249,101,252,56,255,161,255,8,2,51,3,218,2,2,2,109,2,104,4,38,5,135,3,187,1,122,253,233,248,219,248,23,250,18,252,182,250,111,250,122,251,137,253,40,254,193,253,126,252,118,253,56,254,119,255,31,0,240,1,154,4,50,4,24,3,196,3,79,6,93,6,58,5,190,4,107,4,174,2,255,0,5,254,169,253,96,254,178,254,199,253,174,252,130,252,147,252,77,253,250,251,158,250,233,249,61,253,196,1,24,3,176,1,197,255,68,0,212,1,242,1,146,3,
166,4,192,5,224,5,26,2,167,255,126,255,50,254,18,254,122,254,0,254,189,254,112,255,132,254,157,254,105,254,201,255,20,2,2,2,35,1,226,0,161,0,151,255,16,0,41,0,27,0,57,255,246,255,158,2,188,3,71,3,198,1,167,0,213,255,233,254,20,254,200,253,143,254,211,253,219,252,231,252,211,252,25,253,138,254,17,0,49,2,205,3,115,2,220,1,131,1,148,1,27,2,16,2,138,1,81,2,227,0,178,254,241,253,121,253,145,254,163,254,48,254,12,254,41,254,31,254,141,255,244,255,147,0,162,0,15,0,64,0,222,0,134,1,181,0,172,255,93,255,77,255,38,255,184,254,169,255,165,0,
9,0,228,255,97,0,105,1,133,0,83,255,254,255,249,1,7,2,122,2,181,2,249,1,235,0,253,0,16,1,196,0,94,0,219,0,98,0,156,255,118,255,201,254,121,255,96,0,247,255,45,255,26,254,188,253,43,253,129,252,153,253,19,255,212,255,187,0,73,1,68,1,72,2,193,2,13,3,254,1,147,0,68,0,216,255,119,255,77,0,244,255,215,254,88,254,37,254,4,254,136,253,237,253,7,255,48,0,198,0,55,0,238,0,64,2,25,2,45,1,89,0,40,0,109,0,117,0,165,255,109,255,229,255,175,0,237,255,31,0,4,0,50,255,17,255,223,254,44,255,22,255,57,255,20,255,152,255,65,255,
42,255,13,255,50,255,34,0,219,255,175,255,133,0,197,0,38,0,41,255,177,255,245,0,97,0,163,255,41,0,21,1,206,0,176,255,38,255,230,255,224,254,81,254,184,255,225,0,38,0,30,0,201,255,86,0,105,0,37,0,130,0,208,0,205,0,101,0,69,0,39,0,90,0,42,1,163,0,239,255,61,0,228,255,193,255,172,255,32,255,193,255,115,255,17,255,130,255,138,255,24,255,189,254,48,255,90,0,161,0,238,255,93,0,14,1,231,0,122,0,24,0,44,1,57,1,172,0,194,0,99,1,147,0,122,255,221,255,114,255,59,255,251,254,40,0,241,0,210,0,53,0,214,0,60,1,122,0,14,0,
212,0,109,1,112,0,79,255,7,0,202,0,238,255,226,254,204,254,46,255,239,254,91,254,234,254,45,255,138,254,233,254,1,0,33,1,244,0,70,1,209,0,107,0,3,0,199,255,236,255,219,255,203,255,180,255,82,255,73,255,171,255,182,255,206,255,121,255,236,254,34,0,188,0,28,0,176,255,110,0,252,0,223,0,183,0,56,1,249,0,8,0,123,0,124,0,64,0,197,255,244,255,136,255,215,254,168,254,129,255,238,255,100,255,74,255,79,0,123,0,135,255,95,255,218,255,48,0,34,0,219,255,139,0,250,0,21,0,199,255,119,0,159,0,210,255,108,255,73,255,144,255,30,255,229,254,82,255,126,255,
103,255,250,255,201,0,57,0,85,0,138,0,74,0,129,0,214,0,59,1,107,1,4,1,92,0,64,0,88,255,85,255,133,255,97,255,230,254,229,254,213,254,14,255,91,255,190,255,6,0,68,0,28,0,55,0,91,0,98,0,177,0,205,0,150,0,79,0,135,0,192,0,3,1,154,0,60,0,93,0,36,0,183,255,116,255,181,255,229,255,155,255,119,255,155,255,222,255,104,255,46,255,218,255,122,0,149,0,154,0,175,0,51,0,187,255,244,255,54,0,91,0,118,0,123,0,25,0,200,255,138,255,125,255,166,255,200,255,255,255,241,255,193,255,235,255,198,255,174,255,238,255,18,0,14,0,157,255,130,255};

  static const unsigned char wav_ok2[] = {147,0,187,255,130,0,40,0,115,0,248,254,104,3,160,254,79,254,210,3,154,254,193,253,59,1,177,0,129,254,219,3,69,254,121,254,29,1,72,1,184,255,64,0,121,0,205,255,113,3,21,20,121,23,76,19,185,13,50,7,45,242,35,223,36,226,108,234,190,241,120,246,209,249,14,252,173,253,207,254,167,255,78,0,202,0,25,1,95,1,112,1,8,2,56,2,77,2,131,2,124,2,155,2,176,2,170,2,165,2,153,2,139,2,165,2,171,2,175,2,143,2,112,2,105,2,101,2,65,2,72,2,18,2,244,1,235,1,211,1,165,1,184,1,103,1,68,1,63,1,32,1,1,1,5,1,210,0,172,0,
209,0,127,0,60,0,175,0,232,255,32,0,125,0,205,254,173,0,196,255,222,253,190,2,246,252,223,252,124,5,77,250,113,254,217,4,61,247,216,3,132,1,11,246,87,9,44,250,108,248,162,13,170,243,143,251,68,14,15,242,4,254,45,10,237,243,85,0,185,3,82,246,40,2,44,254,50,247,39,3,129,251,87,250,237,4,75,250,80,253,239,4,57,252,111,0,152,2,54,253,34,2,0,0,247,254,52,1,180,1,238,2,158,249,3,0,244,254,183,250,170,3,114,253,55,1,186,252,247,242,113,3,210,4,193,252,124,10,200,4,25,0,159,14,233,0,215,248,75,255,78,239,50,241,100,3,122,1,225,5,
30,9,218,0,36,3,47,2,169,250,69,0,149,251,235,246,97,255,50,5,75,5,243,6,184,2,38,0,95,5,2,2,242,5,131,8,76,2,141,251,162,246,159,244,45,249,194,250,186,0,67,5,213,0,44,255,134,3,155,4,17,5,215,0,163,252,30,254,100,1,35,254,226,250,70,249,132,247,205,246,134,251,188,2,223,255,58,253,39,254,16,1,78,2,79,5,53,8,38,4,245,3,105,6,234,0,205,251,173,251,153,250,120,249,82,252,211,0,143,3,145,2,77,2,105,4,67,4,159,1,231,253,106,251,5,251,88,248,176,249,150,248,138,248,109,252,206,253,214,254,79,5,33,9,33,8,156,3,167,2,
48,255,231,255,175,255,197,252,22,253,105,251,26,250,8,254,54,1,60,0,49,255,67,0,15,3,188,1,194,253,89,2,217,2,118,253,23,1,248,5,247,2,59,1,91,1,224,0,17,1,73,1,12,253,104,253,60,255,119,254,16,254,153,255,121,0,250,255,67,254,74,253,186,253,210,253,127,255,199,2,206,2,172,1,248,1,74,2,13,2,72,1,110,2,214,3,10,0,70,253,31,253,205,253,218,251,106,252,21,0,23,1,223,2,166,1,90,3,84,7,1,12,99,7,132,254,150,0,246,255,170,0,159,0,114,1,156,2,78,4,82,5,125,5,100,4,192,3,128,3,11,2,134,2,61,1,18,255,223,0,
70,254,41,253,169,255,245,251,62,254,156,0,17,253,132,1,18,1,40,254,55,3,131,255,6,254,35,3,173,254,89,0,237,3,1,0,43,1,200,1,210,255,68,1,174,1,153,1,141,1,197,255,219,255,194,255,33,255,229,255,1,0,132,255,118,255,215,255,10,0,119,0,23,0,254,255,140,0,221,0,50,1,18,1,147,0,239,255,124,255,56,255,136,254,3,254,13,254,77,254,86,254,18,254,23,254,136,254,3,255,147,255,91,0,195,0,199,0,38,0,12,255,221,254,127,254,111,254,158,254,45,255,101,255,250,254,115,254,47,254,35,254,246,253,233,253,186,253,150,253,215,253,133,254,31,255,106,255,62,255,
15,255,64,255,203,255,1,0,94,0,135,0,99,0,246,255,224,255,156,255,132,255,80,255,32,255,102,255,218,255,52,0,95,0,136,0,102,0,66,0,43,0,44,0,52,0,56,0,179,0,3,1,177,0,48,0,38,0,29,0,230,255,158,255,175,255,32,0,47,0,73,0,24,0,183,255,80,255,28,255,48,255,78,255,172,255,45,0,98,0,169,255,36,255,15,255,116,255,209,255,197,255,124,255,91,255,142,255,160,255,194,255,250,255,90,0,170,0,4,1,90,1,172,1,206,1,148,1,117,1,227,0,236,255,123,255,134,255,174,255,215,255,30,0,78,0,140,0,169,0,153,0,129,0,85,0,65,0,129,0,
57,1,141,1,157,1,120,1,4,1,142,0,10,0,174,255,162,255,129,255,148,255,208,255,239,255,4,0,250,255,176,255,88,255,229,254,214,254,238,254,84,255,211,255,231,255,188,255,134,255,58,255,2,255,215,254,205,254,205,254,234,254,67,255,140,255,214,255,99,0,193,0,213,0,255,0,39,1,60,1,83,1,56,1,40,1,255,0,243,0,229,0,164,0,101,0,98,0,80,0,32,0,59,0,88,0,77,0,55,0,36,0,229,255,179,255,175,255,150,255,182,255,221,255,23,0,81,0,99,0,115,0,130,0,177,0,165,0,85,0,64,0,87,0,65,0,45,0,30,0,66,0,115,0,109,0,38,0,237,255,
212,255,180,255,200,255,218,255,216,255,230,255,232,255,190,255,165,255,156,255,114,255,57,255,2,255,54,255,112,255,158,255,212,255,223,255,235,255,236,255,245,255,3,0,7,0,57,0,54,0,14,0,242,255,240,255,245,255,192,255,125,255,64,255,34,255,73,255,117,255,108,255,105,255,103,255,107,255,145,255,194,255,237,255,242,255,33,0,72,0,55,0,43,0,45,0,37,0,12,0,217,255,154,255,131,255,152,255,141,255,129,255,120,255,112,255,117,255,157,255,189,255,248,255,46,0,95,0,140,0,157,0,171,0,173,0,146,0,115,0,87,0,36,0,237,255,185,255,192,255,245,255,237,255,232,255,229,255,211,255,
210,255,205,255,171,255,229,255,56,0,35,0,33,0,31,0,44,0,63,0,81,0,94,0,101,0,93,0,82,0,61,0,45,0,33,0,32,0,32,0,34,0,43,0,41,0,33,0,21,0,3,0,246,255,238,255,238,255,236,255,240,255,5,0,21,0,32,0,33,0,25,0,28,0,29,0,28,0,33,0,37,0,54,0,66,0,72,0,67,0,44,0,27,0,10,0,250,255,237,255,229,255,236,255,253,255,13,0,24,0,19,0,11,0,0,0,246,255,229,255,218,255,220,255,225,255,239,255,254,255,3,0,255,255,245,255,231,255,220,255,211,255,205,255,208,255,217,255,231,255,247,255,250,255,253,255,249,255,243,255,
232,255,222,255,216,255,219,255,222,255,222,255,224,255,218,255,213,255,215,255,206,255,203,255,201,255,204,255,217,255,227,255,239,255,249,255,250,255,245,255,244,255,245,255,248,255,254,255,252,255,252,255,250,255,9,0,246,255,31,0,220,255,66,0,163,255,142,0,64,255,31,1,189,254,219,2,124,252,243,0,161,7,250,240,191,9,216,3,1,244,158,2,83,255,90,255,222,10,43,251,105,255,14,11,211,234,54,12,22,2,126,248,188,5,40,245,228,2,203,4,114,1,138,2,181,244,36,13,180,250,161,0,245,0,59,254,70,2,59,246,150,4,70,7,39,254,55,252,25,6,211,254,244,252,74,249,70,7,153,253,
113,248,47,7,253,253,85,2,105,4,232,3,54,248,58,252,43,1,105,1,40,5,102,0,218,246,85,3,16,0,176,4,200,254,105,251,143,5,55,251,236,253,159,3,194,254,120,1,178,254,242,254,86,6,244,254,246,254,207,1,58,250,178,1,1,2,78,0,25,252,116,251,55,3,44,253,34,2,161,6,113,1,230,0,110,250,79,1,136,253,232,0,253,253,152,254,100,1,176,1,11,1,195,1,105,253,207,1,175,255,107,252,55,5,13,254,67,252,136,253,173,0,240,2,97,2,130,2,135,255,238,254,113,254,160,255,196,255,177,1,65,2,12,0,11,255,229,1,158,1,194,255,213,255,99,255,121,255,200,253,
45,254,85,2,134,1,26,255,14,3,238,253,165,1,181,254,187,0,2,0,246,251,242,0,167,255,154,255,222,1,145,0,78,7,85,244,202,247,211,255,142,8,74,1,186,9,170,7,251,251,104,250,63,252,194,248,31,251,254,253,169,255,1,9,98,3,199,5,118,2,169,1,62,249,213,249,84,247,157,245,146,249,62,2,150,4,14,6,87,7,102,8,121,1,206,253,81,247,246,248,248,250,51,253,113,4,22,4,26,5,54,5,168,4,0,1,62,252,229,249,210,249,153,253,136,254,112,0,27,2,224,4,32,4,117,4,148,2,233,254,53,253,229,251,115,251,37,253,76,255,152,3,141,6,164,4,177,3,151,1,
202,255,79,254,94,254,51,255,120,254,193,255,119,1,148,2,56,2,8,2,206,2,76,0,213,254,226,253,210,253,223,254,166,254,208,0,237,1,187,1,28,1,3,255,63,253,90,252,32,253,170,255,141,2,24,3,205,2,212,3,174,0,132,254,95,253,40,254,219,254,132,255,207,255,152,255,194,1,17,1,191,0,73,0,69,254,227,253,209,254,70,0,16,0,32,1,221,1,48,2,84,2,164,0,98,0,152,255,222,254,123,255,46,0,236,255,144,255,20,0,17,0,180,254,248,253,54,254,233,255,138,0,110,1,116,2,140,1,225,0,17,0,6,0,163,255,213,255,68,0,230,0,253,255,51,0,160,0,230,254,
250,254,182,254,57,255,54,255,100,255,148,255,19,0,140,255,48,255,248,255,71,255,234,254,151,255,6,255,163,255,242,254,68,255,238,255,119,255,34,255,120,254,170,254,141,255,224,255,226,0,121,0,104,0,178,0,169,0,39,0,235,255,165,255,50,0,202,0,197,0,126,1,135,0,33,0,97,255,125,255,114,255,36,0,21,1,180,0,156,255,16,255,139,255,152,255,175,255,55,1,105,2,64,0,237,255,1,2,145,3,254,2,224,0,81,0,197,0,141,255,93,0,220,1,132,2,147,3,153,2,170,1,71,2,202,1,93,0,203,255,27,255,204,254,24,1,118,2,37,3,124,1,137,0,115,255,96,0,98,254,
7,253,60,254,232,254,125,0,24,1,6,1,248,0,25,0,180,255,143,0,58,255,92,255,2,255,24,255,151,0,116,1,143,2,216,1,129,1,134,0,183,0,184,0,227,0,51,0,245,254,90,255,179,255,81,255,138,255,236,254,34,254,58,254,143,254,39,0,221,255,144,255,217,254,157,254,67,254,151,255,229,255,240,255,177,0,20,0,59,255,48,0,93,0,253,255,184,255,9,0,129,0,76,0,217,0,241,1,180,2,168,1,14,0,34,0,13,0,35,0,56,0,2,0,109,255,141,254,13,255,171,255,181,255,164,255,77,255,59,255,15,255,65,255,223,255,238,255,158,255,131,254,114,254,227,254,129,0,77,0,
73,255,50,255,231,253,69,254,188,254,0,0,122,0,71,0,57,255,48,255,189,255,39,0,67,0,36,255,40,0,55,0,17,0,240,255,234,255,8,0,56,0,71,0,62,0,65,0,31,0,24,0,246,255,251,255,19,0,41,0,74,0,86,0,106,0,102,0,70,0,66,0,8,0,249,255,7,0,243,255,240,255,237,255,237,255,239,255,6,0,20,0,32,0,34,0,127,255,234,254,151,255,102,0,85,0,135,0,194,255,48,0,0,0,22,0,107,0,13,0,129,0,176,255,29,0,79,0,39,0,6,0,212,255,189,255,215,255,117,255,144,255,142,255,131,255,116,255,195,255,249,255,118,0,70,0,200,255,228,255,
245,255,105,0,222,0,108,0,123,0,24,1,178,0,192,0,64,1,86,1,89,1,185,0,208,0,236,0,24,1,84,0,102,0,77,0,86,0,129,0,51,0,199,0,58,0,236,255,253,255,80,0,69,0,106,0,163,255,228,255,48,0,48,0,173,255,143,255,159,255,218,255,242,255,105,0,181,0,204,0,143,0,23,0,108,255,138,255,255,255,216,255,145,255,241,255,186,0,206,1,24,2,74,1,233,255,117,254,215,253,117,253,24,254,84,255,198,0,67,1,214,0,64,0,192,255,105,255,97,255,92,255,210,254,255,254,242,254,250,254,66,255,2,255,239,254,218,254,41,254,170,253,84,253,150,253,248,253,253,254,
30,0,3,1,151,1,45,2,40,2,4,2,41,2,20,2,215,1,176,1,64,1,128,0,197,0,16,0,100,255,159,254,255,253,181,253,23,254,9,255,156,255,124,0,1,1,123,0,52,255,187,254,238,254,160,255,77,1,10,2,72,2,70,1,211,5,32,17,181,17,141,14,91,10,253,6,96,252,198,235,169,232,49,237,137,242,8,247,190,249,79,252,150,253,163,254,215,255,121,0,254,0,152,1,196,1,75,1,169,0,51,0,244,255,90,0,229,0,59,2,49,3,215,3,19,4,76,4,14,5,247,4,242,4,51,4,213,3,83,3,216,2,88,2,254,1,252,1,105,1,24,1,158,0,79,0,185,255,82,255,
85,255,122,255,212,255,210,255,76,255,234,254,30,254,11,254,11,254,82,254,44,254,131,254,197,254,127,254,149,254,138,254,89,254,37,254,103,254,172,254,63,255,44,255,206,254,150,254,113,254,152,254,148,254,108,254,138,254,23,254,76,254,62,254,195,254,76,255,124,255,215,255,222,255,201,255,184,255,131,255,194,255,98,255,231,254,45,255,150,255,254,255,68,0,55,0,58,0,80,0,100,0,228,0,48,1,24,1,234,0,32,1,54,1,115,1,109,1,144,1,122,1,25,1,174,0,189,0,207,0,3,1,218,0,219,0,27,1,241,0,216,0,119,0,155,0,34,0,48,0,94,0,88,0,111,0,26,0,200,255,
113,255,155,255,225,255,63,0,119,0,137,0,242,0,224,0,238,0,247,0,242,0,185,0,92,0,102,0,198,0,183,0,213,0,231,0,189,0,119,0,63,0,252,255,227,255,157,255,164,255,195,255,162,255,190,255,107,255,71,255,11,255,243,254,180,254,226,254,252,254,14,255,243,254,35,255,6,255,33,255,56,255,135,255,185,255,164,255,235,255,244,255,193,255,169,255,136,255,113,255,195,255,245,255,16,0,68,0,189,255,207,255,82,255,3,255,198,254,173,254,227,254,255,254,39,255,70,255,103,255,141,255,139,255,153,255,133,255,190,255,237,255,25,0,91,0,105,0,147,0,159,0,87,0,252,255,193,255,207,255
};
  static const unsigned char wav_prev[] = {255,255,2,0,255,255,252,255,254,255,2,0,1,0,2,0,255,255,0,0,3,0,254,255,5,0,9,0,0,0,249,255,244,255,241,255,249,255,9,0,8,0,20,0,16,0,6,0,23,0,10,0,251,255,244,255,229,255,238,255,254,255,252,255,253,255,5,0,8,0,13,0,11,0,33,0,23,0,11,0,244,255,216,255,213,255,230,255,230,255,2,0,237,255,5,0,20,0,250,255,45,0,13,0,42,0,220,255,56,0,100,255,206,255,230,0,192,254,41,0,239,0,116,255,212,255,248,0,225,255,13,255,171,0,93,255,109,0,254,0,192,254,179,0,215,255,54,0,146,255,232,255,109,0,184,255,3,0,105,255,
61,0,159,0,200,255,138,255,4,0,117,0,73,0,47,0,3,0,4,0,6,0,62,255,209,255,167,255,61,0,87,0,91,0,25,0,107,255,120,0,11,0,55,0,247,255,170,255,245,255,193,255,95,0,246,255,47,0,186,255,127,255,15,0,90,0,142,0,149,255,209,255,5,0,181,255,5,0,246,255,62,0,248,255,188,255,78,0,31,0,254,255,55,0,115,0,151,255,198,255,193,255,22,0,12,0,11,0,238,255,250,255,67,0,44,0,51,0,159,255,195,255,250,255,21,0,13,0,250,255,57,0,10,0,236,255,21,0,13,0,10,0,199,255,79,0,5,0,190,255,139,255,230,255,71,0,23,0,1,0,
228,255,0,0,8,0,2,0,91,0,53,0,240,255,183,255,221,255,19,0,41,0,211,255,204,255,3,0,18,0,54,0,40,0,23,0,191,255,226,255,189,255,245,255,245,255,143,0,246,255,105,0,53,255,108,1,246,253,194,2,119,252,166,2,233,11,31,226,168,30,174,241,119,235,203,31,135,241,219,252,57,12,175,9,231,223,207,28,45,250,68,238,34,22,134,241,9,246,19,21,182,247,52,252,254,15,70,248,22,242,230,12,17,255,235,252,202,5,163,1,104,247,234,1,13,253,15,0,4,6,212,3,135,247,152,2,26,8,102,243,136,8,243,252,134,1,131,249,19,0,76,0,124,3,24,3,117,1,100,253,
89,251,108,4,59,255,25,2,44,255,174,252,109,255,96,255,111,0,65,5,11,2,189,248,0,2,47,254,180,0,49,2,28,254,216,2,52,255,10,252,183,255,53,3,162,0,27,0,36,1,163,255,89,0,43,254,195,0,122,255,57,255,189,254,231,254,113,0,222,0,251,1,230,0,225,254,101,0,22,0,137,254,205,2,187,255,10,254,234,254,132,255,73,254,230,2,153,2,167,253,104,2,69,253,38,253,153,2,216,255,135,0,199,3,53,251,84,252,240,5,209,254,188,0,190,4,64,254,208,252,53,3,204,252,188,255,127,1,192,251,255,254,31,4,179,255,62,254,202,3,245,251,30,1,133,0,240,0,208,2,
1,0,216,253,19,255,219,254,202,0,17,1,116,0,103,0,244,253,210,254,195,0,100,254,139,1,185,1,80,254,246,255,73,255,149,0,25,1,224,255,244,0,153,255,38,0,117,0,167,1,4,0,41,254,225,252,57,255,236,0,190,0,247,1,186,255,233,254,91,254,27,1,136,0,41,1,209,1,9,255,18,255,240,255,31,0,60,255,185,1,97,255,202,254,56,0,141,254,70,0,45,1,200,254,62,0,61,0,56,255,203,1,32,0,113,0,240,255,247,254,195,0,55,0,211,0,197,1,70,254,4,255,163,254,222,254,247,0,245,255,60,1,4,255,83,255,193,255,53,0,84,1,75,1,220,255,205,255,106,0,
127,255,102,0,184,255,3,0,237,255,61,255,16,0,94,0,97,255,188,255,98,255,185,255,86,0,239,0,122,0,66,0,95,255,209,255,221,255,33,0,39,1,137,0,30,0,112,255,209,254,144,255,50,255,7,0,185,0,170,0,241,255,108,255,101,0,113,0,239,255,86,0,53,0,30,0,141,0,214,255,117,255,22,0,175,255,174,254,160,0,98,0,217,255,196,0,26,255,146,255,58,0,254,255,74,0,134,0,165,255,163,255,71,0,138,255,155,0,118,0,215,255,218,255,217,255,192,255,58,255,174,255,245,255,63,0,69,0,107,0,64,0,23,0,32,0,39,0,95,0,139,0,108,0,80,0,237,255,136,255,
39,255,172,255,199,254,113,0,109,0,126,255,228,255,126,255,37,255,189,255,39,0,240,255,212,0,48,0,64,0,162,0,90,0,241,0,154,0,118,0,226,0,58,0,215,255,196,255,15,255,70,255,254,254,11,255,124,255,0,0,22,1,250,0,179,0,186,0,234,255,114,255,152,255,33,255,107,255,41,255,198,255,42,0,246,255,139,0,69,255,175,254,95,255,195,255,251,255,153,1,209,0,98,1,115,1,199,255,142,0,177,0,84,0,240,0,193,0,246,255,166,255,79,255,25,255,176,254,221,254,248,254,152,255,2,0,26,0,43,0,29,0,178,255,229,255,246,255,79,0,118,0,24,0,39,0,60,0,211,255,
163,255,32,0,125,255,196,255,211,255,163,255,177,255,200,255,11,0,10,0,229,255,81,245,237,248,125,9,41,22,153,26,25,255,232,230,4,0,203,18,83,251,208,229,172,233,8,250,227,0,208,253,3,251,244,244,227,250,142,18,39,18,179,252,105,4,54,27,127,20,25,6,4,7,89,7,162,3,183,5,22,5,43,247,65,238,75,250,171,250,133,233,64,237,204,243,101,238,164,240,132,247,189,247,156,247,182,255,2,7,48,5,247,3,153,12,5,15,240,11,122,15,49,15,245,11,36,12,205,12,52,10,246,4,88,1,153,2,253,255,221,249,1,250,159,249,29,246,222,246,171,248,23,246,97,245,86,248,139,250,
163,250,147,250,91,253,116,255,184,255,186,1,92,2,62,2,249,2,16,4,196,3,61,3,105,3,64,3,158,2,18,2,134,1,197,0,154,0,138,0,240,255,199,255,231,255,114,255,187,255,218,255,202,255,252,255,52,0,2,0,70,0,40,0,246,255,36,0,226,255,196,255,152,255,224,255,138,255,129,255,166,255,65,255,19,255,81,255,251,254,255,254,105,255,94,255,164,255,224,255,35,0,96,0,124,0,129,0,134,0,165,0,155,0,195,0,155,0,134,0,107,0,44,0,56,0,252,255,58,0,229,255,211,255,53,0,153,255,212,255,141,255,111,255,180,255,192,255,206,255,1,0,1,0,34,0,12,0,186,255,
27,0,12,0,211,255,110,0,214,255,39,0,101,0,187,255,13,0,243,255,215,255,248,255,4,0,237,255,32,0,46,0,230,255,237,255,221,255,224,255,238,255,245,255,52,0,29,0,83,0,7,0,253,255,34,0,228,255,10,0,43,0,229,255,254,255,33,0,168,255,229,255,0,0,245,255,10,0,242,255,9,0,21,0,230,255,245,255,239,255,12,0,248,255,216,255,38,0,33,0,20,0,71,0,243,255,245,255,235,255,219,255,232,255,228,255,25,0,24,0,214,255,51,0,21,0,205,255,25,0,218,255,241,255,46,0,250,255,28,0,12,0,253,255,229,255,212,255,230,255,11,0,11,0,21,0,73,0,235,255,
17,0,217,255,220,255,44,0,244,255,43,0,24,0,248,255,17,0,214,255,238,255,0,0,221,255,254,255,33,0,244,255,236,255,27,0,218,255,15,0,248,255,255,255,11,0,22,0,16,0,214,255,11,0,236,255,205,255,2,0,5,0,7,0,253,255,25,0,17,0,4,0,10,0,42,0,238,255,7,0,33,0,6,0,24,0,255,255,241,255,18,0,209,255,209,255,23,0,9,0,20,0,20,0,247,255,220,255,240,255,238,255,234,255,254,255,2,0,21,0,13,0,253,255,250,255,219,255,10,0,31,0,0,0,36,0,25,0,253,255,246,255,9,0,235,255,228,255,254,255,239,255,248,255,13,0,251,255,6,0,
2,0,231,255,15,0,223,255,3,0,9,0,244,255,2,0,2,0,12,0,1,0,240,255,252,255,7,0,21,0,17,0,6,0,247,255,254,255,230,255,241,255,252,255,4,0,40,0,30,0,42,0,241,255,7,0,249,255,229,255,247,255,4,0,39,0,50,0,52,0,36,0,240,255,229,255,15,0,16,0,18,0,27,0,247,255,191,255,189,255,244,255,243,255,189,255,194,255,232,255,213,255,234,255,237,255,203,255,164,255,223,255,8,0,253,255,237,255,47,0,53,0,20,0,40,0,50,0,101,0,153,0,168,0,67,0,252,255,36,0,26,0,234,255,170,255,183,255,190,255,203,255,242,255,246,255,203,255,203,255,
226,255,200,255,214,255,2,0,17,0,32,0,9,0,22,0,23,0,0,0,21,0,43,0,62,0,52,0,251,255,246,255,234,255,255,255,7,0,212,255,223,255,225,255,234,255,3,0,244,255,255,255,2,0,255,255,31,0,8,0,17,0,17,0,3,0,13,0,12,0,2,0,9,0,245,255,234,255,5,0,232,255,1,0,22,0,11,0,12,0,251,255,238,255,231,255,251,255,8,0,18,0,12,0,13,0,253,255,242,255,240,255,238,255,3,0,31,0,9,0,1,0,18,0,3,0,241,255,240,255,240,255,252,255,1,0,5,0,0,0,245,255,236,255,233,255,239,255,243,255,250,255,12,0,13,0,4,0,16,0,
14,0,4,0,253,255,1,0,2,0,10,0,18,0,17,0,11,0,9,0,250,255,253,255,241,255,236,255,248,255,3,0,7,0,5,0,2,0,252,255,249,255,251,255,246,255,4,0,8,0,9,0,22,0,252,255,246,255,234,255,253,255,7,0,253,255,7,0,17,0,0,0,250,255,246,255,247,255,253,255,254,255,24,0,10,0,5,0,11,0,7,0,251,255,3,0,243,255,233,255,9,0,3,0,252,255,7,0,249,255,244,255,1,0,252,255,254,255,2,0,6,0,5,0,7,0,0,0,247,255,253,255,245,255,244,255,6,0,3,0,8,0,10,0,2,0,244,255,245,255,245,255,248,255,14,0,13,0,15,0,
10,0,253,255,238,255,245,255,252,255,0,0,11,0,3,0,4,0,251,255,246,255,2,0,1,0,251,255,8,0,12,0,4,0,0,0,252,255,246,255,249,255,253,255,4,0,10,0,1,0,4,0,252,255,249,255,254,255,248,255,253,255,0,0,253,255,7,0,4,0,2,0,3,0,0,0,1,0,248,255,250,255,10,0,13,0,6,0,14,0,2,0,246,255,249,255,247,255,248,255,252,255,6,0,5,0,1,0,2,0,251,255,250,255,249,255,3,0,7,0,4,0,4,0,8,0,249,255,247,255,255,255,254,255,7,0,6,0,7,0,247,255,250,255,244,255,251,255,243,255,253,255,1,0,246,255,8,0,4,0,
253,255,252,255,11,0,5,0,13,0,11,0,21,0,20,0,251,255,5,0,239,255,253,255,231,255,238,255,249,255,6,0,242,255,20,0,252,255,9,0,18,0,231,255,10,0,2,0,0,0,8,0,13,0,2,0,254,255,237,255,249,255,255,255,7,0,2,0,16,0,249,255,4,0,253,255,245,255,6,0,239,255,7,0,4,0,6,0,10,0,2,0,254,255,240,255,241,255,239,255,239,255,242,255,253,255,2,0,253,255,4,0,3,0,10,0,11,0,4,0,18,0,14,0,14,0,20,0,6,0,1,0,5,0,255,255,7,0,10,0,5,0,2,0,244,255,246,255,241,255,240,255,249,255,249,255,253,255,3,0,
251,255,253,255,254,255,243,255,248,255,255,255,5,0,8,0,9,0,7,0,254,255,252,255,250,255,253,255,5,0,4,0,8,0,0,0,0,0,2,0,249,255,255,255,252,255,0,0,4,0,4,0,2,0,7,0,5,0,255,255,252,255,255,255,251,255,254,255,7,0,4,0,4,0,0,0,254,255,251,255,254,255,251,255,1,0,5,0,4,0,2,0,2,0,254,255,249,255,1,0,253,255,5,0,8,0,2,0,1,0,253,255,252,255,250,255,255,255,0,0,5,0,5,0,254,255,252,255,254,255,251,255,251,255,254,255,2,0,0,0,1,0,1,0,253,255,254,255,255,255,253,255,1,0,2,0,254,255,3,0,
3,0,0,0,0,0,255,255,254,255,255,255,3,0,1,0,4,0,6,0,3,0,255,255,254,255,253,255,249,255,0,0,5,0,2,0,1,0,1,0,253,255,251,255,251,255,255,255,255,255,3,0,6,0,1,0,0,0,0,0,251,255,254,255,2,0,255,255,3,0,2,0,0,0,253,255,253,255,254,255,254,255,0,0,1,0,4,0,0,0,254,255,1,0,254,255,253,255,1,0,1,0,2,0,3,0,3,0,0,0,1,0,0,0,254,255,255,255,255,255,0,0,2,0,2,0,3,0,1,0,254,255,254,255,254,255,1,0,1,0,1,0,2,0,2,0,255,255,253,255,253,255,253,255,0,0,3,0,3,0,
2,0,1,0,0,0,254,255,255,255,0,0,255,255,1,0,2,0,2,0,0,0,254,255,254,255,254,255,254,255,0,0,0,0,1,0,1,0,0,0,1,0,254,255,254,255,0,0,0,0,1,0,3,0,0,0,0,0,0,0,255,255,0,0,255,255,255,255,0,0,2,0,0,0,0,0,0,0,254,255,254,255,1,0,0,0,1,0,2,0,0,0,1,0,0,0,253,255,254,255,255,255,0,0,1,0,1,0,2,0,0,0,0,0,254,255,254,255,0,0,1,0,1,0,1,0,0,0,255,255,0,0,255,255,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,
0,0,1,0,255,255,255,255,255,255,0,0,0,0,255,255,1,0,1,0,1,0,0,0,0,0,0,0,255,255,255,255,0,0,1,0,1,0,1,0,1,0,255,255,255,255,255,255,0,0,1,0,1,0,2,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,1,0,0,0,255,255,0,0,255,255,255,255,0,0,0,0,1,0,1,0,0,0,0,0,255,255,255,255,0,0,1,0,0,0,0,0,1,0,0,0,1,0,255,255,0,0,0,0,255,255,0,0,0,0,1,0,1,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,1,0,1,0,0,0,0,0,255,255,255,255,0,0,1,0,1,0
};
  static const unsigned char wav_next[] = {0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,1,0,0,0,1,0,253,255,2,0,254,255,0,0,2,0,1,0,255,255,253,255,1,0,252,255,8,0,254,255,1,0,1,0,254,255,1,0,8,0,252,255,253,255,1,0,254,255,253,255,9,0,255,255,2,0,1,0,2,0,255,255,2,0,1,0,242,255,250,255,247,255,242,255,6,0,11,0,14,0,9,0,2,0,247,255,250,255,13,0,7,0,5,0,253,255,240,255,236,255,240,255,240,255,236,255,250,255,12,0,13,0,20,0,12,0,8,0,14,0,4,0,9,0,22,0,3,0,8,0,249,255,255,255,238,255,12,0,192,255,94,0,124,255,
173,0,83,255,218,0,214,253,151,3,153,250,106,251,204,29,147,223,172,254,236,19,123,250,155,0,227,252,125,3,118,251,95,250,179,14,48,249,93,0,237,249,117,253,36,15,117,236,6,19,157,248,195,246,104,16,135,253,90,253,95,1,16,248,1,8,90,249,155,2,100,255,49,254,125,3,141,253,250,6,123,246,53,253,89,9,36,0,231,3,129,247,109,4,65,253,74,249,158,7,21,2,100,253,170,6,87,248,226,3,159,255,206,250,237,4,97,251,181,0,223,253,70,1,139,3,202,255,9,255,161,253,168,1,209,0,150,2,47,3,20,251,246,253,211,0,243,255,195,0,102,0,153,1,221,254,174,252,24,0,
157,1,129,0,215,254,141,1,42,1,184,253,45,255,218,0,249,0,7,2,188,255,246,0,202,255,138,253,213,0,215,0,123,253,182,253,211,255,60,0,95,2,13,2,119,255,146,254,96,254,68,1,189,3,210,255,61,255,19,0,50,253,224,255,36,1,147,255,135,1,127,254,86,0,82,0,39,255,25,0,133,254,199,1,83,254,204,2,123,250,141,3,137,255,20,0,239,1,44,2,55,251,10,6,3,0,166,250,118,7,206,245,176,2,161,254,159,3,211,255,89,1,5,252,248,254,95,2,55,255,84,255,10,3,69,0,61,255,72,254,95,255,185,0,20,255,92,1,255,1,76,255,80,0,211,254,45,1,125,255,
19,255,5,0,200,0,107,0,31,0,169,254,7,255,206,255,178,0,253,0,11,1,198,255,101,254,115,255,67,255,43,1,93,1,137,255,78,1,250,0,123,255,171,254,183,254,114,255,164,1,220,0,115,0,116,254,184,254,128,255,78,255,148,1,36,1,88,0,71,0,247,255,105,0,108,255,106,253,66,1,95,0,234,255,12,0,149,255,77,0,185,255,135,0,214,0,240,255,162,0,120,0,231,255,52,255,77,254,202,254,230,255,128,0,57,1,222,0,89,0,215,254,22,0,144,0,55,0,123,0,151,255,55,0,45,255,221,254,248,255,66,255,130,0,236,0,72,1,92,0,28,255,8,0,59,0,226,255,40,0,
48,0,231,255,233,255,228,255,149,255,92,255,139,255,176,255,179,1,224,255,2,0,254,255,191,254,184,255,227,255,135,0,24,1,230,255,139,0,153,255,109,255,62,0,217,255,134,0,92,0,246,255,234,255,99,255,7,0,179,255,65,0,40,0,98,0,51,0,183,255,77,0,98,255,43,255,26,0,73,0,69,0,48,0,47,0,93,0,59,255,204,255,90,0,101,0,251,255,32,0,202,255,21,255,242,255,2,0,174,0,41,0,99,0,175,0,146,255,117,255,234,255,79,0,253,255,197,255,138,0,179,255,147,255,198,255,200,255,179,0,182,255,118,0,129,0,246,255,12,0,167,255,109,255,181,255,13,0,244,255,
137,0,182,255,231,255,208,255,197,255,243,254,47,255,58,1,150,1,248,1,160,255,82,254,220,255,239,0,1,0,51,255,42,255,148,255,233,255,253,255,211,255,230,255,30,0,122,0,111,0,183,255,37,0,96,0,244,255,14,0,82,0,48,0,62,0,240,255,188,255,239,255,230,255,108,0,244,255,196,255,247,255,196,255,243,255,241,255,224,255,37,0,30,0,234,255,47,0,11,0,202,255,244,255,11,0,254,255,29,0,252,255,233,255,255,255,245,255,29,0,174,255,254,255,16,0,176,255,76,0,10,0,240,255,24,0,63,0,18,0,208,255,75,0,238,255,168,255,18,0,251,255,70,0,200,255,1,0,81,0,
183,255,251,255,250,255,231,255,50,0,228,255,60,0,29,0,228,255,40,0,157,255,238,255,38,0,198,255,37,0,163,255,250,255,134,0,207,255,3,0,39,0,199,255,33,0,240,255,250,255,58,0,2,0,11,0,3,0,59,0,31,0,3,0,23,0,190,255,23,0,205,255,84,255,226,255,192,255,155,255,0,0,160,255,235,255,241,255,235,255,65,0,6,0,91,0,114,0,98,0,121,0,181,0,143,0,61,0,135,0,127,0,131,0,100,0,20,0,6,0,142,255,67,255,105,255,39,255,40,255,82,255,35,255,241,254,49,255,94,255,128,255,146,255,208,255,39,0,9,0,90,0,118,0,167,0,43,1,215,0,
119,1,12,1,158,0,5,1,140,0,153,0,94,0,32,0,131,0,240,255,19,0,76,255,31,255,98,255,229,254,119,255,12,255,4,255,72,255,219,254,127,255,113,255,152,255,84,0,27,0,96,0,100,0,130,0,168,0,34,0,130,0,110,0,86,0,104,0,37,0,90,0,18,0,13,0,39,0,243,255,229,255,22,0,9,0,17,0,222,255,234,255,4,0,206,255,61,0,55,0,245,255,29,0,122,0,6,1,110,0,63,255,75,254,35,254,254,254,249,254,239,253,56,253,82,254,201,0,72,3,4,5,130,4,98,3,14,5,27,6,236,3,184,0,247,254,53,254,22,252,5,250,172,248,210,247,230,247,221,248,
47,249,240,248,58,251,215,254,129,0,162,1,255,3,82,6,225,7,88,9,25,10,243,9,143,9,103,9,116,8,49,6,38,4,106,2,48,0,236,253,51,252,31,250,148,248,173,247,38,247,226,246,38,246,221,246,117,248,154,249,21,251,169,252,32,254,172,255,45,1,232,2,219,3,149,4,164,5,254,5,233,5,194,5,64,5,223,4,64,4,102,3,101,2,130,1,172,0,237,255,210,254,87,254,45,254,234,253,162,253,174,253,180,253,234,253,74,254,65,254,174,254,232,254,72,255,179,255,192,255,22,0,49,0,52,0,130,0,105,0,126,0,78,0,53,0,104,0,46,0,34,0,17,0,47,0,39,0,17,0,
6,0,17,0,1,0,5,0,38,0,65,0,34,0,35,0,34,0,247,255,48,0,32,0,242,255,19,0,9,0,24,0,252,255,249,255,227,255,199,255,222,255,225,255,252,255,219,255,225,255,246,255,235,255,253,255,248,255,221,255,20,0,30,0,247,255,18,0,237,255,5,0,38,0,0,0,18,0,252,255,254,255,35,0,255,255,7,0,15,0,253,255,251,255,240,255,0,0,227,255,225,255,27,0,254,255,249,255,10,0,243,255,9,0,244,255,9,0,22,0,254,255,20,0,12,0,240,255,243,255,253,255,5,0,8,0,6,0,17,0,249,255,249,255,235,255,255,255,6,0,235,255,16,0,7,0,247,255,19,0,
244,255,1,0,5,0,246,255,21,0,237,255,245,255,12,0,242,255,246,255,8,0,4,0,250,255,249,255,253,255,247,255,6,0,255,255,15,0,18,0,246,255,25,0,255,255,239,255,5,0,248,255,17,0,5,0,241,255,11,0,240,255,229,255,16,0,250,255,238,255,5,0,0,0,21,0,0,0,251,255,16,0,231,255,14,0,9,0,243,255,245,255,251,255,6,0,230,255,252,255,14,0,252,255,9,0,1,0,4,0,8,0,2,0,23,0,246,255,9,0,17,0,244,255,20,0,247,255,249,255,7,0,238,255,6,0,240,255,254,255,0,0,249,255,19,0,238,255,249,255,7,0,249,255,9,0,247,255,244,255,
3,0,2,0,251,255,250,255,247,255,247,255,252,255,254,255,255,255,245,255,251,255,6,0,255,255,12,0,15,0,5,0,13,0,4,0,17,0,11,0,2,0,18,0,253,255,1,0,4,0,250,255,236,255,236,255,250,255,239,255,4,0,7,0,1,0,255,255,251,255,27,0,15,0,3,0,2,0,253,255,1,0,251,255,0,0,21,0,242,255,9,0,9,0,244,255,12,0,253,255,254,255,246,255,249,255,12,0,248,255,255,255,249,255,244,255,248,255,248,255,15,0,0,0,252,255,239,255,247,255,252,255,248,255,4,0,254,255,0,0,254,255,253,255,4,0,216,255,152,255,104,255,207,255,165,0,94,1,76,1,
153,0,187,0,232,1,120,2,61,1,220,254,100,252,31,251,34,252,187,252,208,250,34,250,154,252,147,255,241,0,187,1,146,3,99,5,209,6,102,8,91,8,47,7,62,7,127,7,78,5,18,2,116,0,2,255,108,252,58,250,115,248,79,246,49,245,114,245,169,245,101,245,173,246,10,249,178,250,131,252,42,255,174,1,195,3,0,6,196,7,168,8,133,9,116,10,193,10,236,9,208,8,192,7,64,6,111,4,182,2,186,0,153,254,252,252,239,251,159,250,90,249,227,248,247,248,5,249,99,249,10,250,197,250,192,251,252,252,40,254,26,255,2,0,253,0,218,1,95,2,199,2,17,3,33,3,20,3,245,2,
170,2,71,2,224,1,117,1,8,1,159,0,61,0,238,255,183,255,138,255,96,255,92,255,92,255,104,255,125,255,127,255,165,255,179,255,189,255,216,255,230,255,240,255,245,255,248,255,237,255,208,255,220,255,206,255,200,255,206,255,195,255,200,255,207,255,200,255,211,255,241,255,248,255,4,0,27,0,33,0,56,0,37,0,35,0,62,0,55,0,63,0,40,0,36,0,26,0,9,0,9,0,1,0,255,255,247,255,236,255,229,255,224,255,228,255,239,255,232,255,238,255,247,255,243,255,246,255,249,255,1,0,252,255,254,255,15,0,14,0,15,0,2,0,252,255,1,0,4,0,1,0,15,0,2,0,1,0,7,0,
255,255,253,255,254,255,1,0,3,0,5,0,8,0,4,0,0,0,255,255,2,0,2,0,3,0,3,0,3,0,251,255,252,255,11,0,2,0,253,255,255,255,253,255,7,0,251,255,251,255,248,255,246,255,0,0,254,255,250,255,244,255,252,255,3,0,3,0,7,0,253,255,254,255,3,0,248,255,253,255,0,0,0,0,7,0,255,255,4,0,248,255,249,255,5,0,255,255,3,0,1,0,4,0,5,0,252,255,3,0,254,255,3,0,4,0,2,0,6,0,0,0,10,0,4,0,251,255,4,0,1,0,2,0,4,0,4,0,12,0,8,0,3,0,12,0,10,0,3,0,3,0,252,255,254,255,1,0,255,255,
254,255,251,255,248,255,250,255,240,255,244,255,243,255,241,255,245,255,240,255,245,255,239,255,244,255,252,255,251,255,9,0,11,0,17,0,13,0,15,0,19,0,13,0,11,0,12,0,13,0,8,0,0,0,248,255,238,255,232,255,233,255,222,255,241,255,255,255,0,0,255,255,246,255,5,0,8,0,10,0,19,0,22,0,24,0,23,0,12,0,11,0,1,0,15,0,25,0,17,0,13,0,13,0,13,0,254,255,254,255,2,0,247,255,235,255,226,255,216,255,207,255,204,255,213,255,224,255,222,255,236,255,249,255,254,255,8,0,18,0,14,0,19,0,24,0,38,0,35,0,19,0,29,0,26,0,19,0,22,0,
8,0,2,0,255,255,253,255,246,255,249,255,247,255,247,255,254,255,251,255,0,0,2,0,255,255,2,0,4,0,252,255,251,255,0,0,4,0,6,0,254,255,244,255,250,255,247,255,250,255,240,255,239,255,253,255,252,255,244,255,243,255,227,255,224,255,228,255,251,255,251,255,248,255,6,0,13,0,37,0,37,0,22,0,26,0,27,0,30,0,24,0,0,0,228,255,240,255,228,255,232,255,222,255,219,255,239,255,11,0,17,0,4,0,33,0,37,0,31,0,34,0,24,0,19,0,15,0,7,0,254,255,9,0,14,0,5,0,244,255,232,255,231,255,230,255,219,255,217,255,212,255,242,255,253,255,250,255,8,0,
23,0,28,0,29,0,23,0,4,0,7,0,14,0,9,0,250,255,247,255,252,255,241,255,236,255,235,255,236,255,240,255,240,255,246,255,248,255,251,255,1,0,254,255,0,0,4,0,1,0,7,0,8,0,10,0,14,0,16,0,13,0,8,0,9,0,5,0,255,255,1,0,4,0,2,0,254,255,0,0,254,255,251,255,251,255,255,255,1,0,255,255,3,0,255,255,3,0,7,0,2,0,1,0,255,255,252,255,252,255,252,255,251,255,253,255,252,255,253,255,255,255,2,0,3,0,2,0,2,0,254,255,254,255,3,0,2,0,3,0,0,0,0,0,3,0,255,255,255,255,250,255,253,255,252,255,246,255,250,255,
248,255,253,255,1,0,3,0,1,0,1,0,1,0,1,0,255,255,2,0,1,0,2,0,3,0,2,0,1,0,4,0,4,0,1,0,5,0,4,0,5,0,6,0,1,0,253,255,1,0,3,0,2,0,7,0,4,0,7,0,0,0,253,255,253,255,0,0,5,0,1,0,255,255,254,255,254,255,251,255,253,255,0,0,3,0,1,0,3,0,253,255,254,255,254,255,251,255,252,255,250,255,253,255,254,255,0,0,1,0,251,255,249,255,254,255,250,255,253,255,253,255,253,255,255,255,254,255,254,255,1,0,1,0,2,0,3,0,253,255,4,0,6,0,1,0,1,0,4,0,254,255,253,255,254,255,253,255,255,255,
0,0,3,0,2,0,0,0,251,255,251,255,2,0,1,0,4,0,6,0,3,0,0,0,3,0,4,0,3,0,2,0,4,0,1,0,2,0,5,0,3,0,1,0,3,0,3,0,3,0,2,0,0,0,2,0,5,0,6,0,0,0,254,255,254,255,1,0,252,255,251,255,248,255,253,255,250,255,252,255,252,255,252,255,249,255,254,255,4,0,5,0,6,0,3,0,3,0,1,0,0,0,2,0,1,0,5,0,6,0,1,0,253,255,252,255,252,255,254,255,251,255,255,255,254,255,255,255,248,255,248,255,250,255,251,255,253,255,1,0,254,255,254,255,255,255,255,255,253,255,252,255,254,255,251,255,255,255,1,0
  };
  static const unsigned char wav_column[] = {1,0,5,0,10,0,2,0,245,255,235,255,247,255,239,255,213,255,230,255,6,0,16,0,5,0,17,0,56,0,83,0,63,0,37,0,68,0,60,0,11,0,233,255,221,255,210,255,175,255,140,255,134,255,155,255,143,255,138,255,181,255,215,255,252,255,36,0,75,0,124,0,144,0,154,0,149,0,140,0,114,0,80,0,43,0,9,0,241,255,204,255,195,255,178,255,168,255,160,255,166,255,186,255,189,255,202,255,221,255,243,255,253,255,7,0,14,0,24,0,27,0,31,0,32,0,31,0,15,0,40,0,11,0,3,0,6,0,6,0,254,255,250,255,8,0,0,0,251,255,238,255,4,0,248,255,1,0,249,255,
2,0,234,255,6,0,7,0,252,255,16,0,249,255,16,0,249,255,13,0,243,255,253,255,9,0,241,255,2,0,247,255,0,0,247,255,3,0,245,255,254,255,252,255,27,0,238,255,36,0,5,0,242,255,1,0,241,255,22,0,241,255,20,0,252,255,239,255,245,255,240,255,219,255,58,0,237,255,254,255,230,255,43,0,239,255,13,0,30,0,21,0,10,0,237,255,5,0,249,255,27,0,250,255,183,255,32,0,194,255,247,255,248,255,15,0,1,0,45,0,249,255,250,255,57,0,235,255,4,0,11,0,224,255,233,255,60,0,255,255,226,255,33,0,237,255,7,0,18,0,29,0,10,0,204,255,32,0,205,255,
26,0,28,0,250,255,14,0,222,255,16,0,252,255,8,0,189,255,250,255,248,255,212,255,31,0,190,255,252,255,14,0,1,0,226,255,49,0,51,0,78,0,103,0,64,0,20,0,237,255,177,0,86,253,175,2,255,254,68,255,145,1,191,254,156,0,60,253,45,2,103,0,176,254,96,2,128,252,235,1,105,255,221,0,138,255,40,0,12,255,108,255,68,3,103,254,22,255,40,0,216,0,238,1,4,253,194,254,65,1,102,1,108,0,143,254,77,0,134,1,63,255,22,254,133,0,190,1,187,254,143,255,192,0,40,2,0,255,192,253,54,1,60,0,107,255,51,255,184,1,115,0,185,254,221,254,125,1,96,0,
238,254,99,0,69,0,227,255,62,255,223,0,224,255,54,255,220,255,127,0,164,255,39,255,38,1,125,0,182,255,188,255,7,1,23,0,200,254,136,0,24,0,179,244,234,254,32,13,196,21,170,255,128,241,7,9,43,9,156,238,101,244,27,249,221,244,3,10,36,221,24,24,224,255,220,248,30,10,102,1,67,26,200,0,98,11,177,242,193,28,16,253,253,249,4,5,179,15,205,243,250,228,221,254,160,1,231,229,134,254,24,5,21,253,29,236,42,0,150,246,49,20,35,3,122,251,183,15,41,1,240,255,115,15,25,3,245,6,109,254,53,1,56,3,161,0,81,254,137,3,139,247,51,253,251,0,82,252,179,250,
255,254,22,0,160,248,255,253,186,253,66,5,54,2,153,255,13,3,212,250,253,254,249,254,44,3,142,9,108,255,133,251,111,251,83,254,216,5,177,252,212,5,173,251,169,3,198,1,185,249,124,6,89,249,245,9,141,249,16,3,163,253,116,1,2,0,109,254,12,255,41,2,121,252,66,1,250,0,33,254,122,0,85,254,216,0,187,255,98,0,154,0,19,1,220,255,166,254,59,255,188,2,181,0,204,1,240,254,189,255,228,252,176,253,206,1,145,1,33,0,143,255,164,255,77,1,250,0,101,1,211,254,49,255,230,255,76,255,25,255,251,0,57,254,253,0,213,253,190,0,76,1,91,0,22,1,241,254,40,0,
152,0,5,255,198,0,88,0,84,254,78,1,39,0,141,1,130,0,83,0,41,0,239,254,95,254,243,253,120,1,116,253,120,1,247,254,111,255,129,1,33,0,140,2,142,0,204,0,74,0,17,254,198,254,197,1,186,0,129,0,4,255,113,254,9,254,244,255,24,1,218,0,75,1,96,254,147,255,142,254,153,0,96,0,144,255,42,0,89,0,220,2,7,1,11,0,182,255,140,254,1,255,129,0,251,254,219,255,172,254,121,254,72,1,32,0,41,1,11,1,159,0,205,0,23,0,94,255,69,0,240,254,54,0,152,0,244,255,9,254,234,255,215,255,81,1,237,0,243,255,108,0,10,254,208,255,103,255,185,255,
159,0,66,0,107,0,152,1,244,255,227,0,108,0,112,255,140,255,45,255,154,0,247,254,5,255,97,255,84,255,79,254,149,1,216,1,145,0,237,0,172,255,163,0,98,255,30,0,164,0,160,255,28,255,10,255,72,0,177,255,251,255,208,255,177,0,141,0,176,255,52,255,124,255,142,255,234,255,120,0,236,0,3,0,154,255,108,0,100,0,160,0,24,0,195,255,68,255,124,0,129,255,178,0,59,255,255,254,34,1,12,1,34,1,114,0,144,1,63,0,42,255,229,254,125,254,103,253,96,253,136,254,92,254,76,0,215,0,162,2,146,2,141,2,11,2,210,0,21,0,241,255,113,255,76,0,156,255,102,0,
208,255,167,255,223,254,167,253,72,253,13,254,121,255,158,255,78,1,149,1,168,0,144,0,251,255,118,0,30,1,78,1,7,2,87,1,159,0,138,255,13,255,232,253,44,254,33,255,61,255,108,255,141,0,130,0,90,0,45,255,184,255,247,255,149,0,235,0,84,0,136,0,22,255,151,255,60,0,53,0,165,0,4,0,72,0,94,0,240,255,101,255,201,255,140,255,247,255,220,255,13,0,30,0,240,255,187,0,103,1,8,0,126,0,92,255,78,255,52,255,147,255,85,0,162,255,174,255,136,255,193,0,165,255,20,0,252,255,246,255,179,0,196,255,231,0,237,255,31,255,243,255,168,255,212,0,166,0,139,0,
244,255,119,0,214,255,114,255,23,255,101,255,174,255,4,0,19,0,78,0,9,0,228,255,27,0,127,0,35,0,42,0,150,0,216,255,6,0,182,255,141,255,9,255,135,255,31,0,12,0,51,0,121,0,130,0,25,0,72,0,91,0,165,255,100,0,88,0,199,255,23,0,170,255,29,0,158,255,195,255,15,0,230,255,9,0,164,255,195,255,188,255,192,255,227,255,157,0,130,0,42,0,139,0,33,0,19,0,115,0,184,255,242,255,155,255,206,255,222,255,136,255,180,255,239,255,73,0,224,255,155,0,52,0,210,255,234,255,168,255,33,0,16,0,44,0,218,255,215,255,27,0,5,0,16,0,192,255,54,0,
39,0,227,255,9,0,87,255,206,255,145,255,23,0,93,0,12,0,171,0,251,255,212,0,236,255,50,0,254,255,146,255,1,0,180,255,242,255,160,255,220,255,247,255,255,255,4,0,26,0,231,255,88,0,234,255,8,0,45,0,212,255,34,0,42,0,57,0,49,0,50,0,227,255,209,255,232,255,8,0,0,0,5,0,203,255,26,0,203,255,234,255,40,0,237,255,10,0,246,255,248,255,22,0,67,0,35,0,247,255,223,255,200,255,195,255,157,255,253,255,244,255,47,0,34,0,26,0,47,0,36,0,251,255,19,0,22,0,25,0,223,255,221,255,254,255,235,255,11,0,3,0,227,255,223,255,23,0,217,255,
245,255,255,255,229,255,229,255,227,255,19,0,112,0,29,0,10,0,4,0,22,0,50,0,209,255,245,255,209,255,209,255,180,255,215,255,249,255,42,0,96,0,245,255,28,0,231,255,22,0,35,0,50,0,40,0,27,0,251,255,226,255,218,255,229,255,28,0,4,0,223,255,46,0,10,0,205,255,251,255,200,255,30,0,245,255,34,0,76,0,9,0,16,0,31,0,235,255,254,255,231,255,197,255,243,255,241,255,235,255,246,255,180,255,241,255,9,0,205,255,30,0,21,0,203,255,101,0,204,255,255,255,62,0,230,255,225,255,36,0,253,255,254,255,35,0,13,0,90,0,186,255,27,0,247,255,184,255,56,0,
223,255,2,0,0,0,227,255,224,255,11,0,17,0,29,0,35,0,16,0,30,0,204,255,245,255,27,0,249,255,25,0,255,255,234,255,47,0,0,0,39,0,49,0,1,0,10,0,190,255,240,255,12,0,232,255,22,0,241,255,226,255,201,255,236,255,238,255,12,0,5,0,36,0,250,255,243,255,52,0,0,0,3,0,5,0,236,255,9,0,10,0,19,0,29,0,0,0,208,255,223,255,200,255,198,255,255,255,246,255,254,255,216,255,220,255,231,255,253,255,37,0,41,0,92,0,26,0,62,0,35,0,30,0,229,255,9,0,25,0,208,255,2,0,53,0,209,255,209,255,235,255,20,0,94,0,187,255,248,255,
26,0,6,0,25,0,194,255,215,255,25,0,219,255,196,255,32,0,236,255,222,255,252,255,22,0,58,0,212,255,235,255,44,0,55,0,77,0,6,0,37,0,252,255,12,0,245,255,211,255,232,255,200,255,253,255,216,255,21,0,231,255,207,255,238,255,224,255,81,0,55,0,9,0,55,0,1,0,248,255,17,0,21,0,29,0,3,0,229,255,4,0,213,255,201,255,217,255,228,255,236,255,245,255,252,255,33,0,15,0,250,255,41,0,9,0,14,0,7,0,25,0,13,0,12,0,240,255,235,255,199,255,226,255,4,0,252,255,242,255,24,0,35,0,18,0,33,0,15,0,32,0,1,0,11,0,253,255,4,0,
38,0,0,0,2,0,254,255,211,255,221,255,243,255,241,255,5,0,246,255,235,255,10,0,238,255,19,0,18,0,1,0,55,0,240,255,26,0,4,0,224,255,238,255,219,255,240,255,7,0,2,0,4,0,228,255,3,0,0,0,253,255,244,255,29,0,3,0,253,255,17,0,4,0,1,0,2,0,14,0,255,255,216,255,237,255,230,255,3,0,26,0,21,0,249,255,232,255,245,255,227,255,248,255,6,0,11,0,49,0,11,0,22,0,16,0,23,0,6,0,233,255,24,0,231,255,242,255,0,0,0,0,246,255,238,255,12,0,254,255,245,255,17,0,40,0,250,255,4,0,241,255,238,255,3,0,239,255,8,0,
35,0,252,255,232,255,10,0,253,255,34,0,249,255,232,255,6,0,221,255,11,0,16,0,22,0,8,0,0,0,9,0,253,255,5,0,252,255,16,0,225,255,242,255,21,0,232,255,239,255,251,255,12,0,25,0,246,255,245,255,7,0,228,255,10,0,14,0,232,255,253,255,252,255,33,0,23,0,249,255,248,255,253,255,219,255,239,255,248,255,240,255,250,255,243,255,252,255,7,0,5,0,11,0,26,0,7,0,26,0,9,0,13,0,19,0,255,255,15,0,244,255,253,255,250,255,250,255,240,255,255,255,4,0,14,0,253,255,250,255,7,0,11,0,28,0,254,255,252,255,247,255,242,255,243,255,245,255,12,0,
19,0,255,255,238,255,253,255,234,255,233,255,230,255,237,255,4,0,14,0,26,0,0,0,234,255,228,255,254,255,14,0,30,0,25,0,6,0,22,0,0,0,246,255,234,255,242,255,1,0,255,255,0,0,21,0,236,255,225,255,232,255,181,255,190,255,175,255,126,255,172,255,211,255,169,255,2,0,114,0,123,0,21,1,49,1,119,1,25,2,41,2,197,1,168,1,10,2,134,0,53,0,219,255,93,254,188,254,199,253,170,252,13,253,68,253,144,252,31,253,248,253,21,254,15,255,199,255,11,0,221,0,59,1,61,1,190,1,217,1,164,1,135,1,68,1,36,1,194,0,130,0,109,0,29,0,14,0,2,0,
243,255,9,0,240,255,243,255,233,255,223,255,240,255,245,255,251,255,16,0,251,255,244,255,7,0,24,0,13,0,233,255,226,255,247,255,7,0,17,0,13,0,253,255,238,255,243,255,229,255,246,255,252,255,250,255,0,0,247,255,2,0,222,255,225,255,242,255,234,255,12,0,2,0,16,0,23,0,33,0,22,0,28,0,19,0,13,0,18,0,6,0,3,0,228,255,235,255,220,255,226,255,239,255,244,255,232,255,238,255,0,0,243,255,3,0,255,255,255,255,252,255,252,255,245,255,246,255,248,255,250,255,234,255,214,255,225,255,225,255,230,255,247,255,14,0,18,0,17,0,29,0,15,0,22,0,9,0,3,0,
8,0,13,0,19,0,0,0,250,255,2,0,252,255,5,0,1,0,251,255,20,0,9,0,5,0,252,255,251,255,247,255,250,255,14,0,5,0,253,255,243,255,242,255,237,255,254,255,250,255,254,255,13,0,9,0,254,255,4,0,9,0,19,0,6,0,7,0,16,0,11,0,11,0,254,255,1,0,253,255,253,255,246,255,240,255,231,255,234,255,236,255,251,255,8,0,4,0,244,255,248,255,244,255,13,0,6,0,10,0,8,0,251,255,14,0,26,0,9,0,1,0,25,0,8,0,13,0,13,0,6,0,23,0,14,0,243,255,245,255,253,255,242,255,244,255,249,255,239,255,246,255,247,255,251,255,244,255,247,255,
247,255,245,255,250,255,249,255,10,0,251,255,2,0,6,0,4,0,255,255,7,0,10,0,10,0,9,0,248,255,248,255,0,0,251,255,5,0,249,255,249,255,7,0,2,0,0,0,242,255,249,255,248,255,254,255,14,0,21,0,5,0,1,0,255,255,248,255,245,255,2,0,2,0,250,255,254,255,250,255,255,255,242,255,237,255,0,0,9,0,9,0,15,0,45,0,47,0,233,255,148,255,159,255,194,255,119,255,2,255,77,255,57,0,74,1,168,1,85,1,33,2,183,2,196,1,210,0,105,0,141,255,144,254,158,253,207,252,212,252,180,252,101,252,59,253,74,254,202,254,173,255,172,0,139,1,66,2,143,2,
159,2,203,2,144,2,30,2,185,1,43,1,162,0,53,0,232,255,164,255,123,255,96,255,82,255,96,255,105,255,129,255,146,255,164,255,191,255,198,255,215,255,229,255,230,255,228,255,232,255,235,255,238,255,247,255,245,255,238,255,238,255,247,255,248,255,245,255,240,255,239,255,239,255,245,255,246,255,247,255,250,255,248,255,249,255,246,255,243,255,251,255,255,255,3,0,11,0,1,0,252,255,249,255,227,255,232,255,230,255,226,255,223,255,223,255,212,255,219,255,239,255,5,0,45,0,79,0,110,0,132,0,141,0,153,0,140,0,119,0,80,0,47,0,255,255,200,255,153,255,101,255,56,255,61,255,68,255,72,255
  };
  static const unsigned char wav_click[] = {114,255,206,255,111,0,163,0,40,0,156,255,156,255,93,0,242,0,146,0,179,255,69,255,243,255,202,1,123,3,238,1,79,251,107,242,141,240,5,253,255,16,28,28,242,21,35,5,148,244,151,233,160,228,49,233,244,251,18,21,239,30,43,15,153,246,140,238,236,251,42,12,254,12,126,1,217,249,78,250,17,249,86,243,88,243,243,254,35,13,187,17,83,12,153,6,55,5,107,1,224,246,81,238,66,241,166,251,207,2,202,2,236,255,79,254,155,253,15,253,184,255,88,8,220,16,248,15,195,5,79,251,139,247,67,249,66,251,87,251,77,252,213,255,182,2,32,2,197,0,247,1,248,3,72,3,82,255,83,251,
97,250,240,251,101,253,3,254,11,255,150,0,152,1,25,2,132,3,120,5,118,5,55,3,11,1,11,1,166,1,237,255,92,252,218,250,187,252,43,255,149,255,253,254,25,255,126,255,32,255,216,254,128,255,139,0,189,0,35,0,255,255,186,0,25,2,192,2,22,2,71,0,149,254,26,254,160,254,106,255,187,255,157,255,109,255,187,255,150,0,110,1,205,1,159,1,43,1,137,0,237,255,156,255,133,255,131,255,117,255,97,255,39,255,228,254,4,255,123,255,217,255,249,255,26,0,64,0,237,255,107,255,123,255,14,0,57,0,12,0,86,0,61,1,161,1,31,1,70,0,149,255,223,254,114,254,13,255,123,0,
199,1,26,2,174,1,206,0,216,255,29,255,190,254,150,254,98,254,108,254,201,254,103,255,20,0,159,0,245,0,245,0,248,0,19,1,224,0,35,0,54,255,3,255,110,255,2,0,38,0,30,0,24,0,30,0,221,255,89,255,50,255,210,255,197,0,21,1,217,0,162,0,200,0,102,0,77,255,102,254,141,254,115,255,252,255,243,255,223,255,56,0,190,0,3,1,254,0,246,0,244,0,131,0,155,255,190,254,148,254,206,254,255,254,33,255,147,255,23,0,87,0,89,0,132,0,184,0,170,0,75,0,25,0,19,0,30,0,29,0,34,0,38,0,34,0,11,0,4,0,13,0,31,0,21,0,216,255,163,255,
207,255,55,0,96,0,5,0,131,255,36,255,244,254,248,254,120,255,109,0,46,1,59,1,187,0,89,0,79,0,65,0,201,255,67,255,3,255,48,255,94,255,114,255,180,255,48,0,127,0,165,0,214,0,87,1,164,1,115,1,195,0,231,255,243,254,63,254,16,254,99,254,221,254,110,255,26,0,222,0,98,1,154,1,104,1,204,0,210,255,29,255,216,254,248,254,13,255,107,255,225,255,55,0,43,0,33,0,127,0,239,0,15,1,159,0,51,0,239,255,0,0,232,255,165,255,114,255,125,255};
  if (jsvIsStringEqual(id,"OK"))
    return jsvNewNativeString((char*)&wav_ok[0], sizeof(wav_ok));
  if (jsvIsStringEqual(id,"OK2"))
    return jsvNewNativeString((char*)&wav_ok2[0], sizeof(wav_ok2));
  if (jsvIsStringEqual(id,"PREV"))
    return jsvNewNativeString((char*)&wav_prev[0], sizeof(wav_prev));
  if (jsvIsStringEqual(id,"NEXT"))
    return jsvNewNativeString((char*)&wav_next[0], sizeof(wav_next));
  if (jsvIsStringEqual(id,"COLUMN"))
    return jsvNewNativeString((char*)&wav_column[0], sizeof(wav_column));
  if (jsvIsStringEqual(id,"CLICK"))
    return jsvNewNativeString((char*)&wav_click[0], sizeof(wav_click));
  return 0;
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioGetFree",
  "generate" : "jswrap_pb_audioGetFree",
   "return" : ["int","How many samples are left free in the ring buffer"]
}
Return how many samples are free in the ring buffer
*/
int jswrap_pb_audioGetFree() {
  return STM32_I2S_GetFreeSamples();
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioStartVar",
  "generate" : "jswrap_pb_audioStartVar",
  "params" : [
      ["wav","JsVar","Raw sound data (16 bit by default)"],
      ["options","JsVar","[Optional] object {overlap:bool, encoding:16(default)/8/'adpcm',blockAlign:512,sampleRate:16000}"]
   ]
}
Play audio straight from a variable of raw WAV data - this adds everything to the buffer at once so blocks

If `overlap:true` is set the waveform will be added to what's already in the audio ringbuffer,
allowing multiple sounds to be played at the same time.

If `encoding:"adpcm"` you may need to specify a `blockAlign` value, but you can populate this with `Pip.audioRead`:

```
var rawInfo = {};
var raw = Pip.audioRead("TEST.wav", rawInfo);
Pip.audioStartVar(raw, rawInfo);
```
*/
typedef struct {
  bool overlap;
  WavInfo wavInfo;
} _jswrap_pb_audioStartVar_cbdata;

static void _jswrap_pb_audioStartVar_cb(unsigned char *data, unsigned int len, void *callbackData) {
  _jswrap_pb_audioStartVar_cbdata *cbdata = (_jswrap_pb_audioStartVar_cbdata*)callbackData;
  if (wavNeedsDecode(&cbdata->wavInfo)) {
    unsigned int wavSamples = wavGetSamples(&cbdata->wavInfo, len);
    wavSamples = wavDecode(&cbdata->wavInfo, (uint8_t*)data, (int16_t*)streamBuffer, len);
    STM32_I2S_AddSamples((int16_t*)streamBuffer, wavSamples, cbdata->overlap);
  } else {
    STM32_I2S_AddSamples((int16_t*)data, len>>1, cbdata->overlap);
  }
}

void jswrap_pb_audioStartVar(JsVar *wav, JsVar *options) {
  debugInfo=false;
  _jswrap_pb_audioStartVar_cbdata cbdata;
  cbdata.overlap=false;
  cbdata.wavInfo.sampleRate = 16000;
  cbdata.wavInfo.blockAlign = 512;
  cbdata.wavInfo.formatTag = WAVFMT_RAW;
  cbdata.wavInfo.sampleSize = 16;
  cbdata.wavInfo.streamOffset = 0;
  if (jsvIsObject(options)) {
    cbdata.overlap = jsvObjectGetBoolChild(options, "overlap");
    JsVar *v = jsvObjectGetChildIfExists(options, "encoding");
    if (v) {
      if (jsvGetInteger(v)==16) { } // default
      else if (jsvGetInteger(v)==8) { cbdata.wavInfo.sampleSize = 8; } // default
      else if (jsvIsStringEqual(v, "adpcm")) {
        cbdata.wavInfo.formatTag = WAVFMT_IMA_ADPCM;
        cbdata.wavInfo.sampleSize = 4;
      }
      jsvUnLock(v);
    }
    int blockAlign = jsvObjectGetIntegerChild(options, "blockAlign");
    if (blockAlign>0) cbdata.wavInfo.blockAlign = blockAlign;
    int sampleRate = jsvObjectGetIntegerChild(options, "sampleRate");
    if (sampleRate>0) cbdata.wavInfo.sampleRate = sampleRate;
  }
  // if (audioStream) {
  //   if (debugInfo) {
  //     jsiConsolePrintf("Closing existing stream\n");
  //   }
  //   f_close(&audioFile);
  //   audioStream = false;
  // }
  STM32_I2S_Prepare(cbdata.wavInfo.sampleRate);
  size_t wavLen;
  if (!jsvGetDataPointer(wav, &wavLen)) cbdata.overlap=false; // only overlap if we know jsvIterateBufferCallback will call _jswrap_pb_audioStartVar_cb *once*
  jsvIterateBufferCallback(wav, _jswrap_pb_audioStartVar_cb, &cbdata);
  STM32_I2S_StreamEnded(); // ensure we start playing even if there wasn't enough data
}


#ifdef LINUX
int px,py,ox,oy;
void lcdFSMC_blitStart(JsGraphics *gfx, int x, int y, int w, int h) {
  ox=x;
  oy=y;
  px=0;
  py=0;
}
void lcdFSMC_setCursor(JsGraphics *gfx, int x, int y) {
  px=x;
  py=y;
}
void lcdFSMC_blitPixel(unsigned int col) {
  if (py+oy>319 || px+ox>479) {
    jsiConsolePrintf("OOB pixel %d,%d\n", px+ox, py+oy);
  } else
    graphicsSetPixel(&graphicsInternal, px+ox, py+oy, col);
  px++;
}
void lcdFSMC_blitEnd() {
}
#endif

void jswrap_pb_videoFrame() {
  if (!videoStream) return;
  //JsSysTime tStart = jshGetSystemTime();
  //if (debugInfo) jsiConsolePrintf("Stream 0x%04x, %d\n", streamPacketId, streamPacketLen);
  streamPacketRemaining = 0;
  streamPacketBufferLen = streamPacketLen+8; // 8 bytes contains info for next stream
  if (streamPacketLen > STREAM_BUFFER_SIZE) {
    streamPacketRemaining = streamPacketBufferLen-STREAM_BUFFER_SIZE;
    streamPacketBufferLen = STREAM_BUFFER_SIZE;
  }
  size_t actual = 0;
  //jsiConsolePrintf("=========== FIRST READ %d (%d)\n", ((size_t)streamBuffer)&7, streamPacketBufferLen);
  f_read(&videoFile, streamBuffer, streamPacketBufferLen, &actual);
  if (streamPacketId==AVI_STREAM_AUDIO) {
    if (streamPacketRemaining) {
      jsiConsolePrintf("Audio stream too big for streamBuffer\n");
      jswrap_pb_videoStop();
    } else {
      if (wavNeedsDecode(&videoInfo.audio)) {
        int spaceNeeded = wavGetSamples(&videoInfo.audio, streamPacketLen)*2;
        if (spaceNeeded+streamPacketBufferLen > STREAM_BUFFER_SIZE) {
          jsiConsolePrintf("Encoded Audio stream too big for streamBuffer\n");
        } else {
          int16_t *decodedBuffer = (int16_t*)&streamBuffer[streamPacketBufferLen]; // just put decoded data at the end of the data we read into the stream buffer
          int samples = wavDecode(&videoInfo.audio, streamBuffer, decodedBuffer, streamPacketLen);
          STM32_I2S_AddSamples((int16_t*)decodedBuffer, samples, false);
        }
      } else {
        STM32_I2S_AddSamples((int16_t*)streamBuffer, streamPacketLen>>1, false);
      }
    }
  } else if (streamPacketId==AVI_STREAM_VIDEO) {
    lcdFSMC_blitStart(&graphicsInternal, startX,startY,videoInfo.width,videoInfo.height);
    int x=0, y=videoInfo.height-1;
    uint8_t *b = streamBuffer;
    uint8_t *endBuffer = &streamBuffer[streamPacketBufferLen];
    while (b < endBuffer) {
      // Loop doing RLE until end *or* we have more data and no RLE command could use up more than we have left
      uint8_t *nearlyEndOfBuffer = streamPacketRemaining ? &streamBuffer[streamPacketBufferLen-260] : endBuffer;
      while (b < nearlyEndOfBuffer) {
        // next RLE byte!
        uint8_t num = *(b++);
        if (num==0)  { // RLE code is 0 -> escape code for commands
          uint8_t cmd = *(b++);
          if (cmd==0) { // 0 = EOL
            x=0;
            y--;
            lcdFSMC_setCursor(&graphicsInternal, x+startX,y+startY);
          } else if (cmd==1) {
            //jsiConsolePrintf("end of bitmap!\n");
            b = endBuffer;
            // but why is there data after the EOB opcode??
          } else if (cmd==2) { // 2 = DELTA
            x += *(b++);
            y -= *(b++);
            lcdFSMC_setCursor(&graphicsInternal, x+startX,y+startY);
          } else {
            bool extraByte = cmd&1; // copy is padded
            while (cmd--) {
              lcdFSMC_blitPixel(videoInfo.palette[*(b++)]);
              x++;
            }
            if (extraByte) b++; // trailing 0 if
          }
        } else { // just a run of pixels
          uint8_t col = *(b++);
          while (num--) {
            lcdFSMC_blitPixel(videoInfo.palette[col]);
            x++;
          }
        }
      }
      // check if we need to refill our buffer
      if (streamPacketRemaining) {
        uint32_t amountToShift = (uint32_t)(b-streamBuffer) & ~7ul; // aligned to the nearest word (STM32 f_read fails otherwise!)
        uint32_t leftInStream = streamPacketBufferLen - amountToShift;
        memmove(streamBuffer, &streamBuffer[amountToShift], leftInStream); // move data back
        b -= amountToShift;
        streamPacketBufferLen = leftInStream;
        uint32_t bufferRemaining = STREAM_BUFFER_SIZE-leftInStream;
        uint32_t len = streamPacketRemaining;
        if (len>bufferRemaining) len=bufferRemaining;
        //jsiConsolePrintf("=========== READ %d (%d)\n", leftInStream, leftInStream&3);
        f_read(&videoFile, &streamBuffer[leftInStream], len, &actual);
        streamPacketRemaining -= len;
        streamPacketBufferLen += len;
      }
    }
    lcdFSMC_blitEnd();
    if (debugInfo) {
      //jswrap_pb_videoStop(); // first frame only
      //JsSysTime tEnd = jshGetSystemTime();
      //jsiConsolePrintf("%dms\n", (int)jshGetMillisecondsFromTime(tEnd-tStart));
    }
  } else {
    // unknown stream - assume end
    if (videoRepeats) { // seek to beginning and load first stream ID+len
      f_lseek(&videoFile, (uint32_t)(videoInfo.streamOffset)); // go back to start of video data
      streamPacketBufferLen=8;
      f_read(&videoFile, streamBuffer, streamPacketBufferLen, &actual);
      streamPacketId = *(uint16_t*)&streamBuffer[2]; // +0 = '01'/'00' stream index?
      streamPacketLen = *(uint32_t*)&streamBuffer[4]; // +0 = '01'/'00' stream index?
      jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamLooped");
    } else { // else stop
      //jsiConsolePrintf("Unknown stream ID");
      jswrap_pb_videoStopLetAudioRun();
    }
  }
  // get IDs for next stream
  streamPacketId = *(uint16_t*)&streamBuffer[streamPacketBufferLen-6]; // +0 = '01'/'00' stream index?
  streamPacketLen = *(uint32_t*)&streamBuffer[streamPacketBufferLen-4]; // +0 = '01'/'00' stream index?
  if (streamPacketId==AVI_STREAM_VIDEO) {
    // the next frame is a video frame, so ensure we parse it at the right time
    // if the frame is audio we want to parse it ASAP
    videoNextFrameTime += videoFrameTime;
  }
}

void jswrap_pb_audioFrame() {
  if (!audioStream) return;
  unsigned int wavChunkSize = wavGetReadLength(&audioInfo);
  unsigned int wavSamples = wavGetSamples(&audioInfo, wavChunkSize);
  int freeSamples = STM32_I2S_GetFreeSamples();
  //if (debugInfo) jsiConsolePrintf("%d free\n", freeSamples);
  if (freeSamples <= wavSamples)
    return; // if there's not space yet, don't do anything

  size_t actual = 0;

  f_read(&audioFile, streamBuffer, wavChunkSize, &actual);
  //if (debugInfo) jsiConsolePrintf("A%d\n", actual);
  if (actual) {
    if (wavNeedsDecode(&audioInfo)) {
      int16_t *decodedBuffer = (int16_t*)&streamBuffer[wavChunkSize]; // just put decoded data at the end of the data we read into the stream buffer
      int samples = wavDecode(&audioInfo, streamBuffer, decodedBuffer, actual);
      STM32_I2S_AddSamples((int16_t*)decodedBuffer, samples, false);
    } else {
      STM32_I2S_AddSamples((int16_t*)streamBuffer, actual>>1, false);
    }
  } else if (audioRepeats) {
    f_lseek(&audioFile, (uint32_t)(audioInfo.streamOffset)); // go back to start of audio data
    jswrap_pb_sendEvent(JS_EVENT_PREFIX"streamLooped");
  } else {
    // jsiConsolePrintf("End of WAV\n");
    STM32_I2S_StreamEnded(); // ensure we start playing even if we didn't think we'd buffered enough yet
    jswrap_pb_audioStopLetRun(); // Stop parsing, let audio finish
  }
}

void graphicsInternalFlip() {
  // No offscreen buffer (yet), no need to flip
}

void es8388_write_reg(int r,int d) {
  unsigned char data[2] = {(uint8_t)r,(uint8_t)d};
  jshI2CWrite(EV_I2C1, 0x10, 2, data, true);
}
int es8388_read_reg(int r) {
 unsigned char data[2] = {(uint8_t)r};
 jshI2CWrite(EV_I2C1, 0x10, 1, data, true);
 jshI2CRead(EV_I2C1, 0x10, 1, data, true);
 return data[0];
}
void es8388_check_err() {
  if (jspHasError()) {
    jsiConsolePrintf("ES8388 I2C Error\n");
    execInfo.execute &= (JsExecFlags)~EXEC_ERROR_MASK;
    jsvUnLock(jspGetException());
  }
}


/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "setVol",
  "generate" : "jswrap_pb_setVol",
  "params" : [
      ["vol","int",""]
   ]
}
*/
void jswrap_pb_setVol(int volume) {
#ifndef LINUX
  if (jshPinGetValue(SD_POWER_PIN)==0) {
    jsExceptionHere(JSET_ERROR, "Can't change volume when DAC is powered off");
    return;
  }
  if (volume > 33) volume = 33;
  if (volume < 0) volume = 0;
  es8388_write_reg(0x2E, volume); // 46 LOUT1 (33 = max)
  es8388_write_reg(0x2F, volume); // 47 ROUT1
  es8388_write_reg(0x30, volume); // 48 LOUT2 (33 = max)
  es8388_write_reg(0x31, volume); // 49 ROUT2
  es8388_check_err();
#endif
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "writeDACReg",
  "generate" : "jswrap_pb_writeDACReg",
  "params" : [
      ["reg","int",""],
      ["value","int",""]
   ]
}
Writes a DAC register with a value
*/
void jswrap_pb_writeDACReg(int reg, int value) {
#ifndef LINUX
  if (jshPinGetValue(SD_POWER_PIN)==0) {
    jsExceptionHere(JSET_ERROR, "Can't write DAC register when it is powered off");
    return;
  }
  es8388_write_reg(reg & 0xFF, value & 0xFF); // DAC mute
  es8388_check_err();
#endif
}

/*JSON{
    "type" : "staticmethod",
  "class" : "Pip",
  "name" : "readDACReg",
  "generate" : "jswrap_pb_readDACReg",
    "params" : [
        ["reg","int",""]
    ],
    "return" : ["int","The current register value"]
}
Returns the current value of a DAC register
*/
int jswrap_pb_readDACReg(int reg) {
#ifndef LINUX
  if (jshPinGetValue(SD_POWER_PIN)==0) {
    jsExceptionHere(JSET_ERROR, "Can't read DAC register when it is powered off");
    return 0;
  }
  int v =  es8388_read_reg(reg & 0xFF);
  es8388_check_err();
  return v;
#else
  return -1;
#endif
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "setDACPower",
  "generate" : "jswrap_pb_setDACPower",
  "params" : [
      ["isOn","bool",""]
   ]
}
Enable/disabled the DAC power supply (which also powers the audio amp and SD card)
*/
void jswrap_pb_setDACPower(bool isOn) {
  if (!isOn) {
    jswrap_E_unmountSD(); // Close all files and unmount the SD card
#ifndef LINUX
    SDIO_DeInit(); // Properly shut down the SD interface
    jshPinSetState(SD_CLK_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN); // SD card pins have external pullup resistors to 3V3D_M, which is turned off when the SD_POWER_PIN is low, so we should pull them down to help discharge 3V3D_M
    jshPinSetState(SD_CMD_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    jshPinSetState(SD_D0_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    jshPinSetState(SD_D1_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    jshPinSetState(SD_D2_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    jshPinSetState(SD_D3_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    jshPinSetState(SD_DETECT_PIN, JSHPINSTATE_GPIO_IN_PULLDOWN);
    /*** FIXME *** We should actually put the SPI flash chip into "power down" mode
     * ...but for now, just set the SPI flash pins to pulled-up inputs, to ensure that the CS pin isn't left low.
     *
     * NOTE that this won't work in STANDBY mode for PCB v0.6 (or earlier), as the pins go high-impedance (and there's currently no external pullups).
     */
    jshPinSetState(SPIFLASH_PIN_MOSI, JSHPINSTATE_GPIO_IN_PULLUP); // From PCB v0.7, SPI flash pins now have external pullup resistors to 3V3D
    jshPinSetState(SPIFLASH_PIN_MISO, JSHPINSTATE_GPIO_IN_PULLUP);
    jshPinSetState(SPIFLASH_PIN_SCK, JSHPINSTATE_GPIO_IN_PULLUP);
    jshPinSetState(SPIFLASH_PIN_CS, JSHPINSTATE_GPIO_IN_PULLUP);
#endif
  }
#ifndef LINUX
  jshPinOutput(SD_POWER_PIN, isOn); // Power supply enable for the SD card is also used for the ES8388 audio codec (and audio amp)
#endif
}

/*JSON{
    "type" : "staticmethod",
    "class" : "Pip",
    "name" : "initDAC",
    "generate" : "jswrap_pb_initDAC"
}
Initialise the ES8388 audio codec IC
*/
void jswrap_pb_initDAC() {
  JshI2CInfo dacI2C;
  jshI2CInitInfo(&dacI2C);
  dacI2C.pinSCL = DAC_SCL_PIN;
  dacI2C.pinSDA = DAC_SDA_PIN;
#ifndef LINUX
  if (jshPinGetValue(SD_POWER_PIN)==0) {
    jswrap_pb_setDACPower(1); // Power supply enable for the SD card is also used for the ES8388 audio codec (and audio amp)
    jshDelayMicroseconds(5000);
  }
#endif
  jshI2CSetup(EV_I2C1, &dacI2C);
  jshDelayMicroseconds(1000);
  es8388_write_reg(0x00, 0x80); // Reset the ES8388 control registers
  jshDelayMicroseconds(100);
  es8388_write_reg(0x00, 0x00);
  jshDelayMicroseconds(1000);
  // based on https://cdn.pcbartists.com/wp-content/uploads/2022/12/ES8388-user-guide-application-note.pdf
  // The sequence for Start up play back mode
  es8388_write_reg(0x08, 0x00); // slave mode
  es8388_write_reg(0x02, 0xF3); // power down DEM and STM
  es8388_write_reg(0x2B, 0x80); // Set same LRCK
  es8388_write_reg(0x00, 0x05); // FIXME Set Chip to Play&Record Mode
  es8388_write_reg(0x01, 0x40); // Power analog and IBIAS
  es8388_write_reg(0x04, 0x3C); // Power up DAC, Analog out
  //es8388_write_reg(0x17, 0b0001100); // GW: Set DAC SFI - I2S,16 bit
  es8388_write_reg(0x17, 0); // Set DAC SFI - I2S,24 bit
  es8388_write_reg(0x18, 0x02); // Set MCLK/LRCK ratio (256)
  //es8388_write_reg(0x18, 0b00110); // GW: Set MCLK/LRCK ratio (768) - default
  es8388_write_reg(0x1A, 0x00); // L DAC volume 0dB
  es8388_write_reg(0x1B, 0x00); // R DAC volume 0dB
  es8388_write_reg(0x1C, 0x08); // Enable digital click free power up and down
  es8388_write_reg(0x1D, 0x20); // GW: DAC control - force MONO
  es8388_write_reg(0x19, 0x00); // Unmute DAC (no volume soft ramp, 0x32 uses ramp)
  // Set mixer for DAC out
  es8388_write_reg(0x26, 0x09); // Select LIN2 + RIN2 for output mix
  es8388_write_reg(0x27, 0xC0); // L mixer enable DAC + LIN signals, gain = +6dB
  es8388_write_reg(0x28, 0x38);
  es8388_write_reg(0x29, 0x38);
  es8388_write_reg(0x2A, 0xC0); // R mixer enable DAC + RIN signals, gain = +6dB
  jswrap_pb_setVol(33);         // Set volume: 0x1E = 0dB
  es8388_write_reg(0x02, 0xAA); // power up DEM and STM
  // Doc above also has notes on suspend/etc}
  es8388_check_err();
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "setDACMode",
  "generate" : "jswrap_pb_setDACMode",
  "params" : [
      ["mode","JsVar","Mode string - see below"]
   ]
}
* 'off'/undefined -> off
* 'out' -> output
*/
void jswrap_pb_setDACMode_(DACMode mode) {
#ifndef LINUX
  if (jshPinGetValue(SD_POWER_PIN)==0) {
    jsExceptionHere(JSET_ERROR, "Can't set DAC mode when it is powered off");
    return;
  }
  if (mode == DM_OFF) {
    es8388_write_reg(0x0F, 0x24); // ADC Mute
    es8388_write_reg(0x19, 0x36); // DAC Mute
    es8388_write_reg(0x02, 0xF3); // Power down DEM and STM
    es8388_write_reg(0x03, 0xFC); // Power down ADC
    es8388_write_reg(0x04, 0xC0); // Power down DAC L/ROUT
  } else if (mode == DM_Output) {
    es8388_write_reg(0x0F, 0x20); // Unmute ADC
    es8388_write_reg(0x19, 0x00); // Unmute DAC (no volume soft ramp, 0x32 uses ramp)
    es8388_write_reg(0x04, 0x3C); // Power up DAC, Analog out
    es8388_write_reg(0x02, 0xAA); // power up DEM and STM
  } // TODO: passthru?
  //es8388_write_reg(0x, 0x); //
  es8388_check_err();
#endif
}
void jswrap_pb_setDACMode(JsVar *mode) {
  if (jsvIsUndefined(mode) || jsvIsStringEqual(mode, "off"))
    jswrap_pb_setDACMode_(DM_OFF);
  else if (jsvIsStringEqual(mode, "out"))
    jswrap_pb_setDACMode_(DM_Output);
  else {
    jsExceptionHere(JSET_ERROR, "Unknown mode %q\n", mode);
  }
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "setLCDPower",
  "generate" : "jswrap_pb_setLCDPower",
  "params" : [
      ["isOn","bool",""]
   ]
}
*/
void jswrap_pb_setLCDPower(bool isOn) {
#ifndef LINUX
  lcdFSMC_setPower(isOn);
#endif
}
void jswrap_pb_setLCDBacklightOn() {
#ifdef LCD_BL
  jshPinOutput(LCD_BL, 1);
#endif
}


static void jswrap_pb_periph_off() {
#ifndef LINUX
  jshPinOutput(BAT_PIN_SENSE_EN, 1); // disable C4 - pot/etc
#endif
  jswrap_pb_setDACMode_(DM_OFF); // No need to talk to the DAC - we're about to switch off its power (but doing this does help - GW!)
  jswrap_pb_setLCDPower(0);
  jswrap_pb_setDACPower(0); // The DAC (and audio amp) runs from the same power supply as the SD card (also calls jswrap_E_unmountSD)
  jshI2CUnSetup(EV_I2C1); // disable I2C
  jshPinSetState(DAC_SCL_PIN, JSHPINSTATE_GPIO_IN);
  jshPinSetState(DAC_SDA_PIN, JSHPINSTATE_GPIO_IN);
  jshPinSetState(RADIO_SCL_PIN, JSHPINSTATE_ADC_IN);
  jshPinSetState(RADIO_SDA_PIN, JSHPINSTATE_ADC_IN);
#ifdef LCD_TEARING
  jshPinSetState(LCD_TEARING, JSHPINSTATE_GPIO_IN_PULLDOWN);
#endif
  STM32_I2S_Kill();
}

/*JSON{
    "type" : "staticmethod",
    "class" : "Pip",
    "name" : "off",
    "generate" : "jswrap_pb_off"
}
Enter standby mode - can only be started by pressing the power button (PA0).
*/
void jswrap_pb_off() {
  jswrap_pb_periph_off();
#ifndef LINUX
  void jshTurnOff();
/*  In Standby mode, all I/O pins are high impedance except for:
 *          - Reset pad (still available)
 *          - RTC_AF1 pin (PC13) if configured for tamper, time-stamp, RTC
 *            Alarm out, or RTC clock calibration out.
 *          - RTC_AF2 pin (PI8) if configured for tamper or time-stamp.
 *          - WKUP pin 1 (PA0) if enabled. */
  jshTurnOff();
#else
  jsExceptionHere(JSET_ERROR, ".off not implemented");
#endif
}

/*JSON{
    "type" : "staticmethod",
    "class" : "Pip",
    "name" : "sleep",
    "generate" : "jswrap_pb_sleep"
}
Enter sleep mode - JS is still executed
*/
void jswrap_pb_sleep() {
  if (jsfGetFlag(JSF_DEEP_SLEEP)) {
    jsExceptionHere(JSET_ERROR, "Already sleeping");
  }
  jswrap_pb_periph_off();
#ifndef LINUX
  jshTransmitClearDevice(DEFAULT_CONSOLE_DEVICE); // let's just remove any waiting characters for now
  jshUSARTUnSetup(DEFAULT_CONSOLE_DEVICE);
  jshPinSetState(DEFAULT_CONSOLE_TX_PIN, JSHPINSTATE_GPIO_IN_PULLUP);
  jshPinSetState(DEFAULT_CONSOLE_RX_PIN, JSHPINSTATE_GPIO_IN_PULLUP);
#endif
  jswrap_interface_setDeepSleep(1);
}

/*JSON{
    "type" : "staticmethod",
    "class" : "Pip",
    "name" : "wake",
    "generate" : "jswrap_pb_wake"
}
Wake up the pipboy
*/
void jswrap_pb_wake() {
  if (!jsfGetFlag(JSF_DEEP_SLEEP)) {
    jsExceptionHere(JSET_ERROR, "Already awake");
  }
  jswrap_interface_setDeepSleep(0);
  jshReset(); // reset USART
  jshUSARTKick(DEFAULT_CONSOLE_DEVICE); // re-enable UART TX if we have data
#ifndef LINUX
  jshPinSetState(BAT_PIN_SENSE_EN, JSHPINSTATE_GPIO_OUT_OPENDRAIN); // jshReset could mess this up
  jshPinOutput(BAT_PIN_SENSE_EN, 0); // enable C4 - pot/etc
#endif
  jswrap_pb_setLCDPower(1);
  jswrap_pb_initDAC(); // The DAC (and audio amp) runs from the same power supply as the SD card (also calls jswrap_E_unmountSD)
  STM32_I2S_Init();
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "blitImage",
  "generate" : "jswrap_pb_blitImage",
  "params" : [
      ["img","JsVar",""],
      ["x","int",""],
      ["y","int",""],
      ["options","JsVar","scale(int) or { scale:int, noScanEffect:bool, height:int }"]
   ]
}

If `height` isn't specified the image height is used, otherwise only part of the image can be rendered.
*/
int scanlinePos = 0;
void getPaletteForLine2bpp(int y, uint16_t *pal) {
  int distfromScaline = y-scanlinePos;
  if (distfromScaline<0) distfromScaline=-distfromScaline;
  int n = y&1;
  if (distfromScaline>64) {
    // no overscan effect - too far away
    pal[0] = palette[n][0];
    pal[1] = palette[n][5];
    pal[2] = palette[n][10];
    pal[3] = palette[n][15];
  } else {
    int a = distfromScaline<<2; // 0..255
    pal[0] = graphicsBlendColorRGB565(palette[n][0],palette[n+2][0],a);
    pal[1] = graphicsBlendColorRGB565(palette[n][5],palette[n+2][5],a);
    pal[2] = graphicsBlendColorRGB565(palette[n][10],palette[n+2][10],a);
    pal[3] = graphicsBlendColorRGB565(palette[n][15],palette[n+2][15],a);
  }
}
void getPaletteForLine4bpp(int y, uint16_t *pal) {
  int distfromScaline = y-scanlinePos;
  if (distfromScaline<0) distfromScaline=-distfromScaline;
  int n = y&1;
  if (distfromScaline>64) {
    // no overscan effect - too far away
    for (int i=0;i<16;i++)
      pal[i] = palette[n][i];
  } else {
    int a = distfromScaline<<2; // 0..255
    for (int i=0;i<16;i++)
      pal[i] = graphicsBlendColorRGB565(palette[n][i],palette[n+2][i],a);
  }
}
void jswrap_pb_blitImage(JsVar *image, int x, int y, JsVar *options) {
  int scale = 1, height = 0;
  bool noScanlineEffect = false;
  if (jsvIsObject(options)) {
    scale = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(options, "scale"));
    noScanlineEffect = jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(options, "noScanEffect"));
    height = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(options, "height"));
  } else
    scale = jsvGetInteger(options);
  if (scale<1) scale=1;
  // the highlighted area moves over time...
  if (noScanlineEffect) scanlinePos = -100; // if off, just move scalines offscreen
  else scanlinePos = ((long long)(jshGetMillisecondsFromTime(jshGetSystemTime())*(480/4000.0)) % 640LL) - 110;

  JsGraphics *gfx = &graphicsInternal;
  GfxDrawImageInfo img;
  if (!_jswrap_graphics_parseImage(gfx, image, 0, &img))
    return;
  if (height<=0 || height>img.height) height=img.height;
  JsvStringIterator it;
  jsvStringIteratorNew(&it, img.buffer, (size_t)img.bitmapOffset);
  uint16_t palette[16];
  memset(palette,0,sizeof(palette));
#ifndef LINUX
  if (img.bpp==4) lcdFSMC_blit4Bit(gfx, x, y, img.width, height, scale, &it, palette, getPaletteForLine4bpp);
  else if (img.bpp==2) lcdFSMC_blit2Bit(gfx, x, y, img.width, height, scale, &it, palette, getPaletteForLine2bpp);
  else jsExceptionHere(JSET_ERROR, "Unsupported BPP");
#endif
  jsvStringIteratorFree(&it);
  _jswrap_graphics_freeImageInfo(&img);
}


/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "getAudioWaveform",
  "generate" : "jswrap_pb_getAudioWaveform",
  "params" : [
      ["dst","JsVar",""],
      ["y1","int",""],
      ["y2","int",""]
   ]
}
This copies the contents of the current I2S audio buffer out to an array
that can be rendered to the screen with drawPoly.

Because the array is meant to be `x,y,x,y,x,y` only the second elements are
touched.
*/
void jswrap_pb_getAudioWaveform(JsVar *dst, int y1, int y2) {
  if (!jsvIsArrayBuffer(dst)) {
    jsExceptionHere(JSET_TYPEERROR,"ArrayBuffer expected for 1st arg");
    return;
  }
  int ymid = (y1+y2)/2;
  int16_t *samples = (int16_t*)STM32_I2S_GetSampleBufferPtr();
  int len = jsvGetLength(dst)>>1; // length/2
  JsvArrayBufferIterator it;
  jsvArrayBufferIteratorNew(&it, dst, 1);
  for (int i=0;i<len;i++) {
    int y = ymid + (*samples * (y2-y1) / 32768);
    jsvArrayBufferIteratorSetIntegerValue(&it, y);
    jsvArrayBufferIteratorNext(&it);
    jsvArrayBufferIteratorNext(&it);
    samples += 16; // since we output stereo, 2 samples are always the same so skip an even no.
  }
  jsvArrayBufferIteratorFree(&it);
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "audioIsPlaying",
  "generate" : "jswrap_pb_audioIsPlaying",
  "return" : ["bool","True if audio is currently playing"]
}
*/
bool jswrap_pb_audioIsPlaying() {
  return (STM32_I2S_GetStatus() == STM32_I2S_PLAYING);
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "streamPlaying",
  "generate" : "jswrap_pb_streamPlaying",
  "return" : ["JsVar", "Returns `'video'` if a video is playing, or `'audio'` if audio is playing, `'both'` for both, or `undefined` otherwise."]
}
*/
JsVar *jswrap_pb_streamPlaying() {
  if (videoStream) return jsvNewFromString(audioStream ? "both" : "video");
  if (audioStream) return jsvNewFromString("audio");
  return 0;
}

/*JSON{
  "type" : "staticmethod",
  "class" : "Pip",
  "name" : "setPalette",
  "generate" : "jswrap_pb_setPalette",
  "params" : [
      ["palette","JsVar","A 4 element array of 16 element arrays"]
   ]
}
Set the colour palette used for rendering everything on PipBoy

eg:

```
var pal = [
  new Uint16Array(16),
  new Uint16Array(16),
  new Uint16Array(16),
  new Uint16Array(16)
];
// Orangey
for (var i=0;i<16;i++) {
  pal[0][i] = g.toColor(i/15,i/30,0); // 0: even (bright line)
  pal[1][i] = g.toColor(i/30,i/60,0); // 1: odd (dark line)
  pal[2][i] = g.toColor(i/10,i/20,0); // 0: even scan effect
  pal[3][i] = g.toColor(i/20,i/40,0); // 1: odd scan effect
}
Pip.setPalette(pal);
```
*/
static void jswrap_pb_updateTheme() {
  graphicsTheme.fg = (JsGraphicsThemeColor)palette[0][15];
  graphicsTheme.bg = (JsGraphicsThemeColor)palette[0][0];
  graphicsTheme.fg2 = (JsGraphicsThemeColor)palette[2][15];
  graphicsTheme.bg2 = (JsGraphicsThemeColor)palette[2][0];
  graphicsTheme.fgH = (JsGraphicsThemeColor)palette[0][0];
  graphicsTheme.bgH = (JsGraphicsThemeColor)palette[0][15];
  graphicsTheme.dark = graphicsTheme.bg;
}

void jswrap_pb_setPalette(JsVar *pal) {
  if (!jsvIsArray(pal)) {
    jsExceptionHere(JSET_ERROR, "Expecting array of arrays");
    return;
  }
  for (int i=0;i<4;i++) {
    JsVar *a = jsvGetArrayItem(pal, i);
    if (!jsvIsIterable(a)) {
      jsExceptionHere(JSET_ERROR, "Expecting array of arrays, pal[%d] is %t", i, a);
      jsvUnLock(a);
      return;
    }
    JsvIterator it;
    jsvIteratorNew(&it, a, JSIF_EVERY_ARRAY_ELEMENT);
    for (int c=0;c<16;c++) {
      palette[i][c] = (uint16_t)jsvIteratorGetIntegerValue(&it);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
    jsvUnLock(a);
  }
  jswrap_pb_updateTheme();
}

/*JSON{
  "type" : "init",
  "generate" : "jswrap_pb_init"
}*/
void jswrap_pb_init() {
  // Enable watchdog
  jswrap_espruino_enableWatchdog(15, NULL); // init watchdog, auto mode
  // Set up colour palette
  for (uint16_t i=0;i<16;i++) {
    // normally we're a bit more dim
    uint16_t b = (i*220) >> 6; // 0..63
    palette[0][i] = b << 5; // even
    palette[1][i] = ((b*3)>>2) << 5; // odd
    // overscan - full range
    palette[2][i] = i << 7;
    palette[3][i] = (i*3) << 5;
  }
  jswrap_pb_updateTheme();
  // splash screen
  const unsigned char img_raw[] = {199, 17, 2, 0, 0, 31, 255, 255, 255, 255, 255, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 255, 255, 255, 255, 255, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 255, 255, 255, 255, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 91, 255, 213, 85, 85, 111, 255, 192, 11, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 255, 249, 85, 85, 85, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 253, 0, 0, 0, 191, 253, 0, 127, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 255, 128, 0, 0, 7, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 255, 224, 0, 0, 7, 255, 224, 127, 255, 224, 2, 255, 255, 255, 255, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 255, 248, 0, 0, 0, 63, 254, 0, 107, 255, 255, 255, 232, 0, 191, 255, 255, 224, 127, 255, 255, 248, 0, 0, 63, 255, 255, 255, 255, 255, 254, 7, 255, 255, 192, 47, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 255, 255, 255, 255, 224, 127, 255, 255, 255, 255, 253, 91, 255, 255, 255, 131, 255, 255, 255, 224, 0, 3, 255, 255, 255, 255, 255, 255, 224, 26, 255, 252, 0, 107, 255, 250, 170, 170, 255, 248, 0, 170, 170, 170, 170, 168, 0, 191, 255, 255, 255, 255, 255, 248, 7, 255, 250, 170, 171, 255, 255, 255, 255, 255, 252, 47, 255, 255, 254, 0, 0, 47, 255, 191, 255, 255, 234, 80, 0, 7, 255, 192, 0, 47, 255, 0, 0, 11, 255, 192, 11, 255, 255, 255, 255, 224, 11, 255, 234, 170, 170, 171, 255, 240, 63, 253, 0, 0, 31, 255, 255, 253, 191, 255, 0, 127, 255, 208, 0, 0, 2, 255, 244, 0, 0, 0, 0, 0, 0, 127, 253, 0, 1, 255, 244, 0, 0, 191, 252, 0, 21, 85, 85, 85, 85, 0, 127, 254, 0, 0, 0, 31, 255, 67, 255, 224, 0, 0, 255, 245, 85, 64, 255, 253, 31, 255, 244, 0, 0, 0, 31, 255, 128, 0, 0, 0, 0, 0, 3, 255, 208, 0, 31, 255, 64, 0, 7, 255, 208, 0, 0, 0, 0, 0, 0, 7, 255, 224, 0, 0, 0, 255, 248, 47, 255, 0, 0, 15, 255, 128, 0, 1, 255, 255, 255, 248, 0, 0, 0, 85, 255, 248, 0, 0, 0, 0, 0, 0, 127, 254, 81, 20, 255, 249, 64, 5, 127, 255, 213, 64, 0, 0, 0, 0, 17, 127, 255, 64, 0, 5, 95, 255, 130, 255, 245, 85, 85, 255, 248, 0, 0, 2, 255, 255, 254, 0, 0, 0, 15, 255, 255, 192, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 0, 0, 0, 3, 255, 255, 255, 255, 255, 255, 255, 248, 15, 255, 255, 255, 255, 255, 128, 0, 0, 3, 255, 255, 128, 0, 0, 0, 127, 255, 252, 0, 0, 0, 0, 0, 11, 255, 255, 255, 255, 255, 255, 255, 255, 255, 250, 255, 224, 0, 0, 0, 0, 31, 255, 255, 255, 255, 255, 255, 249, 0, 11, 255, 255, 255, 255, 144, 0, 0, 0, 127, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 255, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 255, 254, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 170, 128, 0, 0, 0, 0, 0, 0};
  JsVar *img = jsvNewNativeString((char*)&img_raw[0], sizeof(img_raw));
  JsVar *g = jsvNewObject(); // fake object for rendering
  jsvUnLock(jswrap_graphics_clear(g, 1));
  graphicsInternal.data.fgColor = graphicsTheme.fg;
  jsvUnLock(jswrap_graphics_drawImage(g, img, (LCD_WIDTH-200)/2, LCD_HEIGHT/2-16, NULL));
  graphicsInternal.data.fontSize = JSGRAPHICS_FONTSIZE_6X8+1;
  graphicsInternal.data.fontAlignX = 1;
  JsVar *s = jsvNewFromString(JS_VERSION);
  jsvUnLock2(jswrap_graphics_drawString(g, s, (LCD_WIDTH/2) + 64, LCD_HEIGHT/2, 0), s);
  jsvUnLock(img);
#ifdef USE_AUDIO_CODEC
  // Initialise audio
  STM32_I2S_Init();
  // Initialise dac
  jswrap_pb_initDAC();
#else
  jsiConsolePrintf("No audio codec - can be enabled by defining USE_AUDIO_CODEC");
#endif
  // force SPI flash pin state anyway
#ifndef LINUX
  jshPinSetState(SPIFLASH_PIN_MOSI, JSHPINSTATE_GPIO_IN_PULLUP);
  jshPinSetState(SPIFLASH_PIN_MISO, JSHPINSTATE_GPIO_IN_PULLUP);
  jshPinSetState(SPIFLASH_PIN_SCK, JSHPINSTATE_GPIO_IN_PULLUP);
  jshPinSetState(SPIFLASH_PIN_CS, JSHPINSTATE_GPIO_IN_PULLUP);

  jshPinOutput(JSH_PORTC_OFFSET+7, 0); // PC7 unused
  jshPinOutput(JSH_PORTC_OFFSET+13, 0); // PC13 unused, right next to clock so tie low
  jshPinOutput(JSH_PORTD_OFFSET+6, 0); // PD6 unused
  jshPinOutput(JSH_PORTD_OFFSET+13, 0); // PD13 unused
#endif
  // turn backlight on after a delay by default
  jsvUnLock(jsiSetTimeout(jswrap_pb_setLCDBacklightOn, 100));

  FRESULT res = FR_NOT_ENABLED;
#ifndef LINUX
  File_Handle f;
  BYTE ff_mode = FA_READ | FA_OPEN_EXISTING;
  if (jsfsInit()) {
    // If we've initialised FS, look for a VERSION file
    if ((res=f_open(&f, "VERSION", ff_mode)) == FR_OK) {
      // if it exists read it and write it to a global VERSION
      char version[10];
      UINT sz=0;
      f_read(&f, version, sizeof(version), &sz);
      f_close(&f);
      version[sz]=0;
      jsvObjectSetChildAndUnLock(execInfo.root, "VERSION", jsvNewFromString(version));
       JsVar *s = jsvVarPrintf("FW %s", version);
      jsvUnLock2(jswrap_graphics_drawString(g, s, (LCD_WIDTH/2) + 64, 10+LCD_HEIGHT/2, 0), s);
      // Now run some JS code which will check if what's in Storage is that file, and if not will update it
      jsvUnLock(jspEvaluate( // We can also force an update by holding power+volume up
"if (require('Storage').read('VERSION')!==VERSION || (BTN2.read()&&BTN10.read())) {"
"  B15.set();" // display on
"  const FILE = 'FW.JS';"
"  let stat = require('fs').statSync(FILE);"
"  let size = stat&&stat.size, f;"
"  try { f = E.openFile(FILE,'r'); } catch (e) {}"
"  if (size && f) {"
"    let d = f.read(4096), o=0;"
"    g.clear(1).setFontMonofonto23().setFontAlign(0,0).setColor('#0f0').drawString('Upgrading...',240,160);"
"    let s = require('Storage');"
"    s.eraseAll();"
"    s.write('.bootcde',d,o,size);"
"    while (d) {"
"      o += d.length;"
"      d = f.read(4096);"
"      if (d) s.write('.bootcde',d,o);"
"    }"
"    s.write('VERSION',VERSION);"
"    g.clear();"
"    E.reboot();"
"  } else {"
"    console.log('Cannot read FW.JS');"
"  }"
"}", true/*static*/));
    }
  }

#endif
  bool hasBootCode = jsfFindFile(jsfNameFromString(".bootcde"), NULL) ;
  if (res || !hasBootCode) {
    JsVar *msg;
    if (res == FR_NO_FILE) msg = jsvNewFromString("NO VERSION FILE");
    else if (res == FR_NOT_ENABLED) msg = jsvNewFromString("NO SD CARD");
    else {
      if (!hasBootCode)
        msg = jsvNewFromString("NO JS FIRMWARE");
      else
        msg = jsvVarPrintf("SD CARD ERROR %d", res);
    }
    graphicsInternal.data.fgColor = graphicsTheme.fg; // green
    graphicsInternal.data.fontSize = JSGRAPHICS_FONTSIZE_6X8+1;
    graphicsInternal.data.fontAlignX = 0;
    jsvUnLock(jswrap_graphics_drawString(g, msg, (LCD_WIDTH/2), LCD_HEIGHT/2+20, 0));
    // 25x25 pixel QR code for https://thewand.co/pip-boy
    const unsigned char qr_raw[] = { 25, 25, 1, 254, 242, 63, 193, 7, 80, 110, 173, 43, 183, 71, 133, 219, 160, 34, 236, 21, 177, 7, 250, 170, 254, 0, 87, 0, 163, 64, 146, 186, 253, 154, 239, 143, 247, 190, 49, 18, 141, 125, 154, 9, 135, 45, 143, 169, 222, 154, 113, 7, 184, 239, 64, 249, 0, 77, 68, 127, 173, 170, 48, 79, 49, 27, 164, 191, 149, 208, 234, 90, 235, 118, 119, 4, 165, 176, 254, 248, 132, 128 };
    JsVar *qr_img = jsvNewNativeString((char*)&qr_raw[0], sizeof(qr_raw));
    JsVar *options = jsvNewObject();
    if (options) {
      jsvObjectSetChild(options, "scale", jsvNewFromInteger(3));
      jsvUnLock(jswrap_graphics_drawImage(g, qr_img, (LCD_WIDTH-76)/2, LCD_HEIGHT/2+31, options));
    }
    jsvUnLock3(msg,qr_img,options);
    msg = jsvNewFromString("thewand.co/pip-boy");
    jsvUnLock(jswrap_graphics_drawString(g, msg, (LCD_WIDTH/2), LCD_HEIGHT/2+111, 0));
    jsvUnLock(msg);
  }
  // clear up graphics
  graphicsInternal.data.fgColor = graphicsTheme.fg;
  graphicsInternal.data.fontAlignX = -1;
  jsvUnLock(g);
}

/*JSON{
  "type" : "kill",
  "generate" : "jswrap_pb_kill"
}*/
void jswrap_pb_kill() {
  jswrap_pb_videoStop();
}

/*JSON{
  "type" : "idle",
  "generate" : "jswrap_pb_idle"
}*/
bool jswrap_pb_idle() {
  bool busy = false;
  if (videoStream) {
    busy = true;
    if (jshGetSystemTime() >= videoNextFrameTime)
      jswrap_pb_videoFrame();
  }
  if (audioStream) {
    busy = true;
    jswrap_pb_audioFrame();
  }
  return busy;
}

/*
RDA5807M RADIO IC FUNCTIONS
- Using software I2C as I2C1 is already in use by the ES8388 codec

var rd=new I2C();
rd.setup({sda: B7, scl:B6});
function rd_write_reg(r,d) {
  rd.writeTo(0x22>>1, [r,(d>>8 & 0xFF),(d & 0xFF)]);
}
function rd_read_reg(r) {
  rd.writeTo(0x22>>1, r);
  let bytes = rd.readFrom(0x22>>1,2);
  return (bytes[0]<<8 | bytes[1]);
}

function rd_init() {
  Pip.setDACMode("out");
  let id = rd_read_reg(0)>>8;
  if (id == 0x58)
    console.log(`RDA5807 ID: 0x${id.toString(16)} (as expected)`);
  else
    console.log(`Unexpected value reading RDA5807 ID: 0x${id.toString(16)}`);
  rd_write_reg(0x02,0x0003); // 0x0001:enable,    0x0002:reset
  rd_write_reg(0x02,0xF001); // 0x8000:output on, 0x4000:un-mute, 0x2000:mono, 0x1000:bass boost
  rd_write_reg(0x03,0x0008); // 0x0008:worldwide band (76-108 MHz)
  rd_write_reg(0x04,0x0600); // 0x0400:reserved,  0x0200:softmute
  rd_write_reg(0x05,0x86AF); // 0x8000:int_mode,  0x0600:seek threshold 6/15, 0x00F:volume 15/15
  rd_write_reg(0x06,0x8000); // 0x8000:reserved
  rd_write_reg(0x07,0x5F1A); // 0x5C00:noise soft blend threshold, 0x0002:soft blend enable
  rd.band=(rd_read_reg(0x03) & 0x000C)>>2;
  switch (rd.band) {
    case 0:
      rd.start = 8700;
      rd.end = 10800;
      break;
    case 1:
      rd.start = 7600;
      rd.end = 9100;
      break;
    case 2:
      rd.start = 7600;
      rd.end = 10800;
      break;
    case 3:
      if ((rd_read_reg(0x07) >> 9) & 0x01) {
        rd.start = 6500;
        rd.end = 7600;
      } else {
        rd.start = 5000;
        rd.end = 7600;
      }
  }
  rd.space=rd_read_reg(0x03) & 0x0003;
  switch (rd.space) {
    case 0:
      rd.chans_per_MHz = 10;
      break;
    case 1:
      rd.chans_per_MHz = 5;
      break;
    case 2:
      rd.chans_per_MHz = 20;
      break;
    case 3:
      rd.chans_per_MHz = 40;
      break;
  }
}

function rd_seek(seekUp) {
  let ctrlReg=rd_read_reg(0x02);
  ctrlReg |= 0x0100; // Seek
  if (seekUp) ctrlReg |= 0x0200; // SeekUp (0=down)
  else ctrlReg &= ~0x0200;
  rd_write_reg(0x02,ctrlReg);
  console.log(`Seeking ${seekUp?"up":"down"}...`);
  var i = setInterval(()=>{
    let status=rd_read_reg(0x0A);
    let chan=status&0x03FF;
    let freq=chan*rd.chans_per_MHz+rd.start;
    console.log(`- ch ${chan} (${freq/100} MHz) ${status&0x2000?"(failed)":(status&0x4000?"found":"")}`);
    if (status&0x6000) clearInterval(i);
  },400);
}

// rd_freq_set(f): tune to frequency in multiple of 10 kHz (e.g. 9930 for 99.3 MHz)
function rd_freq_set(f) {
  if (f<rd.start || f>rd.end) {
    console.log(`Invalid frequency (${f}) - must be between ${rd.start} and ${rd.end}`);
    return;
  }
  let chan=((f-rd.start)/rd.chans_per_MHz) & 0x03FF;
  console.log(`Band:${rd.band} (start:${rd.start}, end:${rd.end}), spacing:${1000/rd.chans_per_MHz} kHz, tuning to ${f/100} MHz (channel ${chan})`);
  let chanReg=(chan<<6) | (rd.band<<2) | rd.space | 0x0010; // 0x0010:tune
  rd_write_reg(0x03,chanReg);
  rd_write_reg(0x03,chanReg); // Need to write it twice (?!)
  var t = 0;
  var i = setInterval(()=>{
    let status=rd_read_reg(0x0A);
    if (status&0x6000) {
      console.log(`- set channel=${status&0x03FF} ${status&0x2000?"(failed)":"OK"}`);
      clearInterval(i);
    }
    if (t++>10) {
      console.log(`Giving up!`);
      clearInterval(i);
      rd_write_reg(0x03,chanReg & ~0x0010); // Stop tuning
    }
  },400);
}

Pip.setDACMode("off");
rd_init();
Pip.setDACMode("out");
rd_freq_set(9800); // Tune to 98.0 MHz
setWatch(()=>rd_seek(1),E1,{repeat:true,edge:"rising",debounce:25});
setWatch(()=>rd_seek(0),E2,{repeat:true,edge:"rising",debounce:25});
*/

/*
AUDIO CODEC INITIALISATION CODE
--------------------------------

function es8388_adda_cfg(dacen, adcen){
  var tempreg = 0;
  tempreg |= ((!dacen) << 0);
  tempreg |= ((!adcen) << 1);
  tempreg |= ((!dacen) << 2);
  tempreg |= ((!adcen) << 3);
  es8388_write_reg(0x02, tempreg);
}

function es8388_output_cfg(o1en, o2en){
  var tempreg = 0;
  tempreg |= o1en * (3 << 4);
  tempreg |= o2en * (3 << 2);
  es8388_write_reg(0x04, tempreg);
}

*/
